Spring源码讲解(四)Spring中bean的属性注入
由于Spring源码过于庞大,文章中不会列出细节,须要大家花时间下去研究哦
获取要注入的属性的源信息
当BeanFactory(AbstractAutowireCapableBeanFactory)调用doCreateBean方法实例化完一个对象之后,会调用第三次后置处理器:
可以看到第三次后置处理器是找寻实现了MergedBeanDefinitionPostProcessor接口的后置处理器执行其postProcessMergedBeanDefinition方法,Spring中关键的两个实现了这个接口的后置处理器是以下两个:
AutowiredAnnotationBeanPostProcessor(处理@AutoWired/@Valued注解的属性注入)
CommonAnnotationBeanPostProcessor(处理@Resource注解的属性注入)
首先来看下这两个后置处理器的源码:
AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition ->
AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata方法
这里通过buildAutowiringMetadata方法获取到了一个InjectionMetadata对象,最后放到了injectionMetadataCache这个Map中,后面这个map,顾名思义就是当作缓存来用的,我们主要看下这个buildAutowiringMetadata方法:
最重要的一段是调用了ReflectionUtils#doWithLocalFields方法:
ReflectionUtils#doWithLocalFields方法主要是通过反射获取到了所有类成员属性Fileds,然后依次调用FieldCallback#doWith方法,我们可以看到实际上这个FieldCallback其实就是外面传进来的一段lambda表达式。通过findAutowiredAnnotation方法获取到AnnotationAttributes对象,放到InjectedElement的list当中(最终这个list会被包装为一个一个InjectionMetadata对象被缓存的上面的那个map中去)。
findAutowiredAnnotation方法就是判断当前Field上面有没有加了@Autowired或者@Value注解,如果加了就获取到注解的源信息,就是上面的AnnotationAttributes对象。
除了查询加了注解的属性,还会查询加了注解的方法,在执行完ReflectionUtils#doWithLocalFields方法之后,还会执行ReflectionUtils#doWithLocalMethods方法,不同的是解析完之后是AutowiredMethodElement对象存起来的。
所以AutowiredAnnotationBeanPostProcessor这个后置处理器就是用来缓存加上了@Autowired或者@Value注解的属性或者方法的源信息的,方便后面注入属性时知道须要注入哪些属性。
CommonAnnotationBeanPostProcessor
流程同AutowiredAnnotationBeanPostProcessor,唯一的不同就是扫描的是@Resource注解,最终存放的InjectedElement是ResourceElement类型的
CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition ->
CommonAnnotationBeanPostProcessor#findResourceMetadata方法 ->
CommonAnnotationBeanPostProcessor#buildResourceMetadata方法
走完第三次的后置处理器之后,那些须要注入的属性或者方法信息就被作为InjectionMetadata对象放到injectionMetadataCache这个map中,后面的属性注入就会用到这个map了。
属性注入
spring的属性注入是在执行完第三此后置处理器之后,就立即执行的,也是在doCreateBean方法中。会调用populateBean方法来执行属性的注入。
populateBean方法的第一段逻辑是执行spring的第五次后置处理器,这个后置处理器主要是确定是否须要注入属性,false表示忽略属性的注入,spring不建议对外使用这个接口,因为代表着这个bean将不再维护内部的属性。
之后判断当前bd如果装配模型是AUTOWIRE_BY_NAME或者AUTOWIRE_BY_TYPE时须要做的一些事情。
处理完AUTOWIRE_BY_NAME或者AUTOWIRE_BY_TYPE的两种情况之后,就是要注入@Autowired注解和@Resource注解标识的bean了,这里就要执行spring的第六次后置处理器InstantiationAwareBeanPostProcessor:
这里关键的两个后置处理器又是之前生成InjectionMetadata的两个后置处理器AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor(他们既实现了MergedBeanDefinitionPostProcessor接口又实现了InstantiationAwareBeanPostProcessor接口)。
看下这两个后置处理器的源码:
AutowiredAnnotationBeanPostProcessor
通过findAutowiringMetadata方法获取须要注入的属性,这里面就是从之前的injectionMetadataCache这个map中直接拿这个InjectionMetadata对象,这个对象中包含了当前bean所有须要注入的属性(通过@Autowired注解标识的)。然后调用InjectionMetadata#inject方法将当前的bean对象(前面通过反射创建的原生对象);bean的名称;以及pvs传进去,这里的pvs是通过AbstractBeanDefinition#setPropertyValues方法设置的额外属性:
InjectionMetadata#inject方法中遍历了所有的InjectedElement元素,执行其inject方法:
从前面的第三次后置处理器中可以知道,这里的InjectedElement对象可能是AutowiredFieldElement或者是AutowiredMethodElement,我们这里以AutowiredFieldElement为例吧。
AutowiredFieldElement#inject方法:
通过DefaultListableBeanFactory#resolveDependency方法获取到真正的对象,然后利用反射赋到当前的bean中去:
所以我们看下这个resolveDependency做了什么:
DefaultListableBeanFactory#resolveDependency方法
resolveDependency方法顾名思义就是解决依赖注入:
point1:
这里会判断当前的这个属性有没有加@Lazy注解,加了的话先返回一个代理的对象出来,后面用时再实例化真正的对象,这里不会再去注入真正的属性。
point2:
真正的去注入属性。
看下这个doResolveDependency方法:
DefaultListableBeanFactory#doResolveDependency方法 ->
这里是解析属性类型是List等其他特殊类型的时候的处理方式,暂时过滤掉,下面再讲。
后面就是执行DfaultListableBeanFactory#findAutowireCandidates方法:
看看里面是如何实现的:
所以上面获取到的matchingBeans就是根据bean的类型从DefaultListableBeanFactory中获取到的所有的以bean名称为key,bean的类型为value的一个map!
当然matchingBeans可能会出现多个的情况,再回到doResolveDependency方法中,这里处理了有多个匹配的bean的情况:
可以看到最后还是通过名称从容器中取出来这个bean来完成属性注入的:
DependencyDescriptor#resolveCandidate方法
上面的doResolveDependency方法中还有一个resolveMultipleBeans方法没有讲,这里是处理属性类型是List等其他特殊类型的情况的:
数组和集合:
@AutoWired
private Object[] objArray;
@AutoWired
private List
还没有评论,来说两句吧...