往期文章:
上一篇文章讲到了bean的实例化过程。bean的实例化完成之后,就要对bean进行属性赋值,然后进行初始化。
一个bean从配置到初始化完成放入容器中,要经历四个阶段:
前两个阶段已经在前两篇文章介绍完,因此本篇文章将重点介绍后面两个阶段,bean的依赖注入和初始化这两大过程。
下面对依赖注入和bean的初始化这两个过程的原理进行解析。
首先是依赖注入的原理解析。
首先要理解与依赖注入相关的三个重要的类PropertyValues、PropertyValue、PropertyAccessor。
下面是这三者的关系图:
Spring再bean的依赖注入的时候,不是处理到一个属性就给一个属性赋值的,而是会把一个bean的属性,以及该属性依赖的对象,封装到一个PropertyValue对象中,然后把PropertyValue放入到PropertyValues中,PropertyValues相当于是存放PropertyValue的容器,里面其实是一个List。
收集好了一个bean的所有的PropertyValue到PropertyValues后,将交给PropertyAccessor属性访问器处理。PropertyAccessor通过 method.invoke(…) 或者 field.set(…) 等反射的方法进行属性赋值。
PropertyAccessor是一个接口,然后BeanWrapper接口又继承了该接口,所以最终实现类就是BeanWrapperImpl。
那Spring是如何解析bean的属性依赖关系,生成PropertyValue并放入PropertyValues中的呢?下面将进行介绍。
首先是byName模式的依赖注入,就是通过属性名propertyName作为beanName,调用**getBean(propertyName)**方法获取依赖对象,然后和propertyName一起封装成PropertyValue对象,放入PropertyValues中。
byType模式的依赖注入比byName稍微复杂:
但是在上面这个逻辑之前,Spring还会回调AutowireCandidateResolver接口实现类的getSuggestedValue方法,该接口是一个扩展点,允许我们对依赖注入上做自定义处理,如果该方法返回值不为空,就会注入我们给定的值,不会往下走上面的逻辑。
所以byType的整体逻辑就如下图:
除了byType和byName两种模式,还有就是通过**@Autowired**注解进行依赖注入。@Autowired注解修饰的属性的依赖注入又 AutowiredAnnotationBeanPostProcessor 这个bean后置处理器进行处理,处理逻辑与byType一致。
接下来是bean的初始化的原理解析。
一共四个步骤:
接下来进行源码走读,对上面的分析进行验证。
依赖注入处理逻辑的入口,位于AbstractAutowireCapableBeanFactory的doCreateBean方法里面的populateBean(beanName, mbd, instanceWrapper) 这一行代码。
populateBean方法里面可以看到byName和byType两种模式的依赖注入的入口,autowireByName方法处理byName模式的依赖注入,autowireByType方法处理byType模式的依赖注入。
下面还有对@Autowired注解修饰的属性的依赖注入的处理入口,实现了InstantiationAwareBeanPostProcessor接口的后置处理器,就调用postProcessProperties方法。
populateBean的整体逻辑如下图:
进入autowireByName方法,看一下byName模式依赖注入的处理逻辑。
**unsatisfiedNonSimpleProperties(mbd, bw)获取当前bean所有待注入的属性 String[] propertyNames,然后遍历propertyNames,通过getBean(propertyName)以propertyName作为beanName从容器中获取,然后调用pvs.add(propertyName, bean)**添加到PropertyValues中。
进入pvs.add(propertyName, bean)。
可以看到就是把属性名和依赖的对象封装成一个PropertyValue对象,放到PropertyValues里面的一个List中。
然后在进去autowireByType方法,看看byType模式的依赖注入的处理逻辑。
可以看到跟byName的区别就是获取依赖对象不再是直接通过getBean方法,而是调用了resolveDependency方法。
resolveDependency方法又调用了doResolveDependency方法。
doResolveDependency方法里面首先调用AutowireCandidateResolver的getSuggestedValue方法尝试获取给定的依赖对象或值value,如果返回的value不为空,就以该value作为要注入当当前属性的值。
然后Map
这一行代码就是判断如果Map的size大于1,则推断出一个合适的beanName。
最后取得最合适的beanName后,还是getBean(beanName)获取依赖对象。
接下来看一下对@Autowired注解修饰的属性的依赖注入,这里会回调所有InstantiationAwareBeanPostProcessor的postProcessProperties方法,AutowiredAnnotationBeanPostProcessor实现了InstantiationAwareBeanPostProcessor接口,因此会进入AutowiredAnnotationBeanPostProcessor的postProcessProperties方法。
进入AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,从metadata.inject(bean, beanName, pvs)这一行代码进去。
继续,从element.inject(target, beanName, pvs)这一行代码进行。
如果@Autowired修饰在字段上,会进入到AutowiredFieldElement#inject方法;如果是@Autowired注解修饰在set方法上,会进入到AutowiredMethodElement#inject方法。
先来看AutowiredFieldElement#inject方法。
在AutowiredFieldElement#inject方法里面,可以看到又是调用beanFactory的resolveDependency方法,所以跟byType的逻辑一样。
如果返回结果不为空,就通过field.set(bean, value)反射注入。
再来看下AutowiredMethodElement#inject方法。
还是调用了beanFactory的resolveDependency方法,与byType的逻辑一样。
如果返回结果不为空,则调用method.invoke(bean, arguments)进行反射注入。
依赖注入的代码走读就到这里,下面就是bean的初始化。
bean的初始化的入口位于AbstractAutowireCapableBeanFactory#doCreateBean方法里面的 exposedObject = initializeBean(beanName, exposedObject, mbd) 这一行代码。
进入initializeBean(beanName, exposedObject, mbd)方法。
可以看到就是原来分析里面的四步,非常清晰。**invokeAwareMethods(beanName, bean)**就是Aware接口的回调,**applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)**就是bean后置处理器before方法的回调,invokeInitMethods(beanName, wrappedBean, mbd) 就是bean的初始化方法的回调,applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName) 就是bean后置处理器after方法的回调。
以上就是依赖注入和bean的初始化的全部内容,下面做一个简单总结。
依赖注入:
bean的初始化: