站在设计者的角度设计populateBean: 主要实现了下面几个功能
- 调用Bean的Setter方法实例去给Bean设置上属性值
- 变量类型的转换,同时还要考虑处理集合类型的情况
+ 配置的时候都是以字符串的形式来配置的
- 处理显式自动装配的逻辑(autowire = byName或byType)
用两个类来做测试,GirlFriend
类中注入了BoyFriend
的实例,BoyFriend
中注入了自己的实例:
1 | java复制代码package com.wjw.dao.impl; |
1 | java复制代码package com.wjw.dao.impl; |
从AbstractAutowireCapableBeanFactory的doCreateBean
方法中进入
1 | java复制代码protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { |
最开始是一些判空逻辑:
接下来的逻辑就是脑图里的第一步了:
1 | java复制代码boolean continueWithPropertyPopulation = true; |
首先判断出boyfriend不是spring内部特殊的bean
1 | java复制代码!mbd.isSynthetic() |
再看下容器里是否已经注册了InstantiationAwareBeanPostProcessors级别的后置处理器,如果有则通过责任链模式调用这些后置处理器的postProcessAfterInstantiation方法
这里InstantiationAwareBeanPostProcessor会在属性注入之前,有最后一次机会去修改bean的属性值,此处也可以决定是否后续的填充步骤
1 | java复制代码continueWithPropertyPopulation = false; |
1 | java复制代码// 如果上面设置continueWithPropertyPopulation = false,表明用户可能已经自己填充了 |
接下来来到:
1 | java复制代码PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); |
pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝,获取BeanDefinition里面为Bean设置上的属性值
返回给pvs的是mbd.getPropertyValues()方法的返回值,
1 | java复制代码public MutablePropertyValues getPropertyValues() { |
MutablePropertyValues类
bean的属性解析主要就是和这个类打交道的
回到populateBean
方法里,第一次解析 pvs 值为空,此时就来到脑图中的第二步,按照名字 or 类型对bean进行自动装配
1 | java复制代码int resolvedAutowireMode = mbd.getResolvedAutowireMode(); |
返回结果是0,表示没有配置上自动装配模式,意味着会跳过populateBean
的自动装配逻辑。
之前介绍postProcessMergedBeanDefinition方法时,被@Value和@Autowired标记的成员变量已经被标记出来了,只差将其注入到bean实例里了,因此就没必要再走一遍解析了,所以就没必要执行if中的逻辑了。
1 | java复制代码if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { |
可以看一看上面两种注入方法的逻辑。
autowireByName:
1 | java复制代码protected void autowireByName( |
先获取非简单类型的属性名称,再根据获取出来的属性名称去依次调用容器的getBean方法获取属性名对应的bean实例,最后将获取到的bean实例连同属性的名称添加到属性列表pvs中,再将bean的依赖关系通过registerDependentBean方法给注册起来。
进入unsatisfiedNonSimpleProperties
方法里:
1 | java复制代码/** |
autowireByType:
1 | java复制代码protected void autowireByType( |
首先也是获得非简单类型属性名称:
1 | java复制代码 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); |
然后再根据属性名获取属性描述符PropertyDescriptor
:
1 | java复制代码PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); |
然后根据属性描述符去获取方法参数对象MethodParameter
:
1 | java复制代码MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); |
之后再根据方法参数对象去获取依赖描述符对象DependencyDescriptor
:
1 | java复制代码DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); |
进入PropertyDescriptor
:
主要就是用来描述bean里的主要属性,可以通过它获取到该属性的getter或setter
回到autowireByType
,
1 | java复制代码MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); |
就是获得属性setter方法实例,保存到MethodParameter
实例中,该实例是封装setter的,方便后续注入,DependencyDescriptor
描述要注入的依赖InjectionPoint
是用来描述注入点的,比如boyfriend中的girlfriend就是一个注入点,girlfriend的类型、setter、注解标签这些信息都可以通过InjectionPoint
来获取,DependencyDescriptor
除了上述的功能外,还保存了一些额外的信息,比如:依赖是否必要
1 | java复制代码public boolean isRequired() { |
是否是延迟加载的:
1 | java复制代码public boolean isEager() { |
相关的一些嵌套级别:
1 | java复制代码public void increaseNestingLevel() { |
回到autowireByType
,获取到DependencyDescriptor
之后就可以进行属性对应的值的解析了
1 | java复制代码// 根据容器的BeanDefinition解析依赖关系,返回所有要被注入的Bean实例 |
autowiredArgument是属性的值,并将其与属性名一起添加到属性列表中
1 | java复制代码pvs.add(propertyName, autowiredArgument); |
之后再注册一下bean之间的依赖关系
1 | java复制代码registerDependentBean(autowiredBeanName, beanName); |
毕竟不是所有的依赖关系都是在配置里显式标注的。注册完成后就完成了该方法
本文转载自: 掘金