zoukankan      html  css  js  c++  java
  • 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;  
  • 相关阅读:
    【故障处理】ORA-12162: TNS:net service name is incorrectly specified (转)
    android studio 编程中用到的快捷键
    java时间格式串
    android Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine.
    linux安装vmware
    x1c 2017 安装mint18的坑——grub2
    x1c2017 8G版 win linux的取舍纠结记录
    python的try finally (还真不简单)
    kafka+docker+python
    json文件不能有注释
  • 原文地址:https://www.cnblogs.com/downey/p/4888219.html
Copyright © 2011-2022 走看看