博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)谈依赖注入
阅读量:5797 次
发布时间:2019-06-18

本文共 3003 字,大约阅读时间需要 10 分钟。

所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。当spring容器启动后,spring容器初始化,创建并管理bean对象,以及销毁它。所以我们只需从容器直接获取Bean对象就行,而不用编写一句代码来创建bean对象。这种现象就称作控制反转,即应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。虽然平时只需要按要求将bean配置到配置文件中,但是了解其实现过程对理解spring的实现原理是有好处的,下面就是模拟spring实现依赖注入的过程。

    首先最简单的就是模拟创建bean实例,实现这个过程需要几个辅助类和辅助方法。有一个最重要的辅助方法就是读取XML的配置,可以利用DOM4J来实现对配置文件的读取,这里假设已经读取到一个List对象beanDefines中去了。读取配置后就需要将读取到的代表一个bean的信息放到一个对象中。这个对象的类就是BeanDefinition(包括id、className和一个装PropertyDefinition对象的List),还一个辅助类就是属性值对象的类PropertyDefinition(包括name属性和ref属性,都是字符串,属性名字和配置文件中的属性名字一致)。这两个辅助类就是普通JavaBean对象,都有getter和setter方法。
      for(BeanDefinition beanDefinition : beanDefines){
          if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
          sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
      }
    如上所示,通过一个for循环对beanDefines进行循环遍历,如果其中的某个BeanDefinition具有正确的类名,怎通过Class.forName创建该类的字节码对象,然后通过newInstance方法创建一个调用默认构造函数
创建出来的对象,然后放入名字为sigletons的Map对象中,它的key是bean定义的id属性的值。以上代码省略了try-catch块和其它相关的定义。从这里可以看出,spring初始化bean时,首先是从配置文件中获取bean的定义信息,然后在通过某种方式创建实例对象。
    创建一个bean的实例出来还只是依赖注入的一小部分前提工作,而最重要的属性还没有被注入到相应的对象中。下面就是一为bean对象注入相应属性值的关键代码,其中分了两种情况注入,一种是通过ref属性注入的,还有一种是经过value属性注入的简单属性(为了注入简单属性,在读取xml配置的时候,也保存属性为value的值,因此propertyDefinition中增加了value属性,用来存储对应的值): 
      for(BeanDefinition beanDefinition : beanDefines){
        Object bean = sigletons.get(beanDefinition.getId());
          if(bean!=null){
            try {
              PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
              for(PropertyDefinition propertyDefinition : beanDefinition.getPropertys()){
                for(PropertyDescriptor properdesc : ps){
                  if(propertyDefinition.getName().equals(properdesc.getName())){
                    Method setter = properdesc.getWriteMethod();
                    if(setter!=null){
                      Object value = null;
                      if(propertyDefinition.getRef()!=null && !"".equals(propertyDefinition.getRef().trim())){
                        value = sigletons.get(propertyDefinition.getRef());
                      }else{
                        value = ConvertUtils.convert(propertyDefinition.getValue(), properdesc.getPropertyType());
                      }
                      setter.setAccessible(true);
                      setter.invoke(bean, value);
                    }
                   break;
                 }
               }
             }
           } catch (Exception e) {
           }
         }
       }
    上面代码中最外层的for循环是依次将属性的值注入进从xml中读取并实例化的bean对象中。下面来分析循环中的一个:首先从集合beanDefines拿出一个BeanDefinition对象,接着从存储实例化的bean对象的Map对象sigletons中取得bean的引用。因为存储bean的key是相应beanDefinition中的id属性,所以可以很简单的通过这个id的值找到对应的实例化的bean对象(此时还为注入任何属性)。程序严谨一点就先判断一下bean是否为空,因为师为bean注入属性,当然先保证它自身的存在。有了bean的实例对象后,就可以跟据bean的字节码码对象生成该bean的属性描述数组ps,这是利用工具类Introspector办到的。然后开始遍历从配置文件读取的bean的定义对象beanDefinition,从中获取某一个属性的描述对象。接下来的关键就是再次通过一个for循环遍历ps的属性描述数组,找到与前面从beanDefinition中获取的属性描述对象名字相同的属性的名字,找到后,通过该ps对象中的属性描述对象利用反射获取setter方法(Method setter = properdesc.getWriteMethod())。简单点说,就是以properdesc的name为依据,去beanDefinition里的属性描述对象里找着相同名字的属性定义对象。如果找到就可以开始执行注入功能了,在这里就可以判断该属性定义对象的ref属性有值还是value对象的值存在,如果是ref,就可以从spring中bean的Map容器找ref属性值的bean对象,如果是value属性的定义,就调用ConvertUtils工具类中的convert方法,将value值转换成bean的属性的类型。最后就是设置setter方法的可访问性(准确的说就是为了能够访问私有的方法),然后利用反射在相应的bean上调用该方法。

转载于:https://www.cnblogs.com/qcxdoit/p/5765263.html

你可能感兴趣的文章
2020年M2M收入达160亿美金 运营商需加强“大数据”能力
查看>>
浙江四家电信运营商联合公告:非实名手机8月15日起停用
查看>>
09年智能手机全球销量已超笔记本
查看>>
云存储:正在带动一场安防存储方式的革命
查看>>
不要再猜Windows Server 2016正式发布时间啦 微软已经公开
查看>>
视频直播能火多久?
查看>>
CYQ.Data 数据框架 应用示例 JSON通讯篇
查看>>
数字化带来的网络安全威胁愈发被重视
查看>>
当华为小米联想争吵之时 中兴却在美国意外成功
查看>>
福建铁通呼叫中心尝试创新用工模式,打造新生团队
查看>>
DigitalOcean添加监控和告警特性
查看>>
个人信息须有问法亮剑的金钟罩
查看>>
CIO:企业内部IT由成本中心转为利润中心探讨
查看>>
Linux系统磁盘分区(逻辑卷LVM)的扩充
查看>>
黄平县开展文化多样性旅游大数据普查
查看>>
《数源思维》提问工具之“语法套”
查看>>
CloudCC用CRM开启企业利润增长开挂模式
查看>>
高并发系统之HTTP缓存
查看>>
阿里大航杯AI电力大赛比赛分享及数加平台,机器学习pai使用经验
查看>>
Avaya出售数据网络业务 聚焦联络中心及统一通讯领域转型
查看>>