• spring IOC源码分析(3)


    1.IOC容器的依赖注入

            Spring中,依赖注入是在用户第一次向IOC容器索要Bean时触发的(通过getBean方法)。

           在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中:

    [java] view plaincopy
     
    1. public Object getBean(String name) throws BeansException {  
    2.         return doGetBean(name, null, null, false);  
    3. }  

            可以看到具体的注入过程转移到doGetBean(String…)中,在这个方法中,它首先从缓存中取,如果单件模式的bean已经被创建,则这种bean请求不需要重复的创建,调用

    [java] view plaincopy
     
    1. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  

            跟踪进入getObjectForBeanInstance(…,null),可以知道因为最后的RootBeanDefinition参数是null,所以执行的是:

    [java] view plaincopy
     
    1. if (mbd == null) {  
    2.     object = getCachedObjectForFactoryBean(beanName);  
    3. }  

            而getCachedObjectForFactoryBean(beanName)中实现,其实现很简单,就是在缓存的bean map中查找bean返回。

            继续回到doGetBean(String…)方法中:

    [java] view plaincopy
     
    1.          //取当前bean的所有依赖bean,这样就会触发getBean的递归调用,直至取到一个没有任何依赖的bean为止  
    2.     String[] dependsOn = mbd.getDependsOn();  
    3.     if (dependsOn != null) {  
    4.         for (String dependsOnBean : dependsOn) {  
    5.             getBean(dependsOnBean);  
    6.                       //注册依赖的bean实例,具体实现过程在DefaultSingletonBeanRegistry中实现,其实就是将依赖的bean添加到依赖的hashmap中  
    7.             registerDependentBean(dependsOnBean, beanName);  
    8.         }  
    9.     }  
    10.     //通过调用createBean来,创建单例bean的实例  
    11.     if (mbd.isSingleton()) {  
    12.         sharedInstance = getSingleton(beanName, new ObjectFactory() {  
    13.            public Object getObject() throws BeansException {  
    14.              try {  
    15.               return createBean(beanName, mbd, args);  
    16.              }  
    17.              catch (BeansException ex) {  
    18.             destroySingleton(beanName);  
    19.             throw ex;  
    20.              }  
    21.                 }  
    22.             });  
    23.             bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
    24.     }  
    25.     //同样调用createBean创建prototype的bean实例  
    26.     else if (mbd.isPrototype()) {  
    27.         // It's a prototype -> create a new instance.  
    28.         Object prototypeInstance = null;  
    29.         try {  
    30.             beforePrototypeCreation(beanName);  
    31.             prototypeInstance = createBean(beanName, mbd, args);  
    32.         }  
    33.         finally {  
    34.             afterPrototypeCreation(beanName);  
    35.         }  
    36.         bean=getObjectForBeanInstance(prototypeInstance,name, beanName, mbd);  
    37. }  

            继续看createBean(…),可以看到在AbstractBeanFactory中它只是个抽象类,具体的实现交给其子类(又见模板模式),进入子类AbstractAutowireCapableBeanFactory中看createBean的具体实现:

    [java] view plaincopy
     
    1. Object beanInstance = doCreateBean(beanName, mbd, args);  

            其具体的实现转到doCreateBean(String…),这里我们看到与依赖注入关系比较密切的方法有createBeanInstance和populateBean。

    [java] view plaincopy
     
    1. BeanWrapper instanceWrapper = null;  
    2. if (mbd.isSingleton()) {  
    3.     instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  
    4. }  
    5. if (instanceWrapper == null) {  
    6.     instanceWrapper = createBeanInstance(beanName, mbd, args);  
    7. }  
    [java] view plaincopy
     
    1. // Initialize the bean instance.  
    2. Object exposedObject = bean;  
    3. try {  
    4.     populateBean(beanName, mbd, instanceWrapper);  
    5.     if (exposedObject != null) {  
    6.         exposedObject = initializeBean(beanName, exposedObject, mbd);  
    7.     }  
    8. }  

            在createBeanInstance中生成了Bean所包含的Java对象,这个对象的生成有很多不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成,生成的方式由相关联的BeanDefinition来指定,进入createBeanInstance方法,有:

    [java] view plaincopy
     
    1. return instantiateUsingFactoryMethod(beanName, mbd, args);  
    [java] view plaincopy
     
    1. return instantiateBean(beanName, mbd);  

            上面是其中的两个实例化方法,上面的是在BeanDefinition的FactoryMethod存在的情况下,使用工厂方法对bean进行实例化。下面一个是使用默认的构造函数对bean进行实例化。我们进入instantiateBean(beanName,mbd),可以看到有:

    [java] view plaincopy
     
    1. return getInstantiationStrategy().instantiate(mbd, beanName, parent);  

            因为getInstantiationStrategy()返回的默认的实例化策略,而默认的实例化策略是CglibSubclassingInstantiationStrategy,也即用cglib来对bean进行实例化。CGLIB是一个常用的字节码生成器的类库,它提供了一系列的API来提供Java的字节码生成和转换功能。

            我们再次回到doCreateBean()中的populateBean方法,看看在实例化Bean对象生成的基础上,spring怎样把这些bean对象的依赖关系设置好,完成整个依赖注入过程。在populateBean中,先是取得在BeanDefinition中设置的property值,这些property来自对BeanDefinition的解析,接着便开始进行依赖注入过程:

    [java] view plaincopy
     
    1. //开始进行依赖注入过程,先处理autowire的注入  
    2. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
    3.             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
    4.   
    5.             //根据bean的名字进行autowire过程  
    6.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
    7.                 autowireByName(beanName, mbd, bw, newPvs);  
    8.             }  
    9.   
    10.             //根据类型type进行autowire的过程  
    11.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
    12.                 autowireByType(beanName, mbd, bw, newPvs);  
    13.             }  
    14.   
    15.             pvs = newPvs;  
    16. }  

             最后在通过applyPropertyValues对属性进行注入:

    [java] view plaincopy
     
    1. applyPropertyValues(beanName, mbd, bw, pvs);  

             接着我们到applyPropertyValues中去看具体的对属性进行解析然后注入的过程,在其中会调用BeanDefinitionValueResolver对BeanDefinition进行解析,

    [java] view plaincopy
     
    1. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);  

             接着为解析值创建一个拷贝,拷贝的数据将会被注入到bean中,它会先对PropertyValue判断,如果其没有经过转换则会调用resolveValueIfNecessary进行解析,然后注入到property中。下面到BeanDefinitionValueResolver中去看一下解析过程的实现,在函数resolveValueIfNecessary中包含了所有对注入类型的处理,以RuntimeBeanReference(其是在对BeanDefinition进行解析时生成的数据对象)为例:

    [java] view plaincopy
     
    1. if (value instanceof RuntimeBeanReference) {  
    2.     RuntimeBeanReference ref = (RuntimeBeanReference) value;  
    3.     return resolveReference(argName, ref);  
    4. }  
    5. //当注入类型为RuntimeBeanReference时,进入resolveReference(…):  
    6. private Object resolveReference(Object argName, RuntimeBeanReference ref) {  
    7.         try {  
    8.             //从RuntimeBeanReference取得reference的名字  
    9.             String refName = ref.getBeanName();  
    10.             refName = String.valueOf(evaluate(refName));  
    11.             //如果ref是在双亲的IOC容器中,那就到双亲IOC容器中去取  
    12.             if (ref.isToParent()) {  
    13.                 if (this.beanFactory.getParentBeanFactory() == null) {  
    14.                     //抛出异常BeanCreationException  
    15.                                              ……  
    16.                 }  
    17.                 return this.beanFactory.getParentBeanFactory().  
    18.                                      getBean(refName);  
    19.             }  
    20.             else {  
    21.                                     //在当前IOC容器中去取bean  
    22.                 Object bean = this.beanFactory.getBean(refName);  
    23.                                 this.beanFactory.registerDependentBean(refName, this.beanName);  
    24.                 return bean;  
    25.             }  
    26. }  

            在上面的实现中,无论是到双亲的IOC容器中去取,还是在当前IOC容器中取,都会触发一个getBean的过程,这就触发了相应的依赖注入的发生。

            这就完成了resolve的过程,为依赖注入准备好了条件。但真正的把Bean对象设置到它所依赖的另一个Bean的属性中去的地方是在BeanWrapper的setPropertyValues中(在分析populateBean的时候有提到),其中处理的属性是各种各样的。setPropertyValues的具体实现是在BeanWrapper的子类BeanWrapperImpl中:

            在doCreateBean中执行完populateBean,完成Bean的生成和依赖注入以后,开始对Bean进行初始化,这个初始化过程包含了对后置处理器的postProcessBeforeInitializtion回调,具体实现在initializeBean方法中:

    [java] view plaincopy
     
    1. Object wrappedBean = bean;  
    2. if (mbd == null || !mbd.isSynthetic()) {  
    3.     wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  
    4. }  
    5.   
    6. try {  
    7.     invokeInitMethods(beanName, wrappedBean, mbd);  
    8. }  
    9. catch (Throwable ex) {  
    10.     //抛出异常BeanCreationException  
    11. }  
    12.   
    13. if (mbd == null || !mbd.isSynthetic()) {  
    14.     wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  
    15. }  
    16. return wrappedBean;  
  • 相关阅读:
    jquery弹出窗口
    js定时器
    jquery树形菜单
    用convert转换参数对比
    jquery常用例子!
    JS总结
    上传简历实现只浏览不下载的效果
    区块链入门(1):搭建(Ubuntu系统)Truffle v3.2.1 开发和测试环境
    URL Routing组件是如何与ASP.NET MVC框架组合起来的
    接单网站收集
  • 原文地址:https://www.cnblogs.com/downey/p/4888219.html
Copyright © 2020-2023  润新知