//判断后继处理器是否已经初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//判断是否需要依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
//如果后继处理器已经初始化完成
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//对所有需要依赖检查的属性进行后处理,但此时还没有依赖检查
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
//如果需要类型检查
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//依赖检查,对应depends-on属性,3.0已经弃用这个属性了
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
//将属性应用到bean中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
总结一下populateBan方法的作用
-
调用InstantiationAwareBeanPostPostProcessor处理器的postProcessAfterInstantiation函数
-
根据注入的类型,byType或者byName来提取依赖的bean,并且统一存入PropertyValues中去
-
应用InstantiatinAwareBeanPostProcessor处理的postProcessPropertyValues的方法,对注入的属性再次处理
-
将找到的属性填充至BeanWrapper中,也就是PropertyValues中去
这里比较重点的就是第二和第四步的注入,其他感觉太难了,看不下去。。。
根据注入的类型进行提取依赖bean
注入的类型有两种
-
byType
-
byName
我们可以给bean去设置注入的类型
这里的自动注入是对依赖的bean进行自动注入,而不是本身。。。
对应的代码为如下
AUTOWIRE_BY_NAME
这是根据名字进行自动注入的方法,也就是依赖的name属性
源码如下
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//获取需要注入的依赖属性,注意这里是获取不是简单类型的,也就是基本数据类型
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//遍历这些依赖属性
for (String propertyName : propertyNames) {
//判断Spring的IOC容器中是不是存在这个bean
//可以看出这就是ByName形式
if (containsBean(propertyName)) {
//调用getBean方法进行创建
//看到这就懂了,单例的时候是怎么递归创建依赖的
//并且怎么去检测循环依赖的
Object bean = getBean(propertyName);
//将生成的bean添加新PropertyValues中
pvs.add(propertyName, bean);
//进行注册该bean
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
logger.trace(“Added autowiring by name from bean name '” + beanName +
“’ via property '” + propertyName + “’ to bean named '” + propertyName + “’”);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace(“Not autowiring property '” + propertyName + “’ of bean '” + beanName +
“’ by name: no matching bean found”);
}
}
}
}
步骤大概如下
-
获取需要依赖的属性
-
遍历需要依赖的属性
-
根据依赖的属性的beanName查看IOC容器里面是否有该bean,体现出了ByName
-
如果不存在该bean,抛错,表示没有找到匹配的bean
-
如果存在该bean,调用getBean方法去创建依赖的bean(又走那一套流程,所以说到底创建bean就是一个递归过程)
-
将创建好的bean放入PropertyValues中
-
对该bean进行注册
整体逻辑没什么,下面来看是如何获取依赖的属性的
unsatisfiedNonSimpleProperties
对应获取依赖的属性具体方法在这里,这个方法会主动排除简单属性,即引用类型和基本数据类型
源码如下
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
//创建一个treeSet进行去重
Set result = new TreeSet<>();
//获取所有的依赖
PropertyValues pvs = mbd.getPropertyValues();
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
//
for (PropertyDescriptor pd : pds) {
//只有写了set方法
//不在不检查依赖的集合中
//不是简单类型
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
//满足条件之后添加进里面
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
看代码比较抽象,所以决定举个栗子
配置文件只是简单的一个注入类型
类也很简单,只是简单地提供了一个set方法注入
下面我们直接看那两个集合是什么
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
结果如下
里面有两个对象
一个是bean自己的class,没有writeMethod
另外一个,关于twoPojo的,而且里面存称了writeMethod正式set方法!!!!
所以可以推测这个集合获取的是需要依赖的属性详情
PropertyValues pvs = mbd.getPropertyValues();
里面的东西如下所示
可以看到,里面完全就是配置文件里面的信息。。。。
所以,这个集合里面存储的是配置文件里面的依赖属性的信息
那么现在,这个for循环来剔除什么,就很容易看出了
回归到我们的for循环
for (PropertyDescriptor pd : pds) {
//只有写了set方法
//不在不检查依赖的集合中
//不是简单类型
//并且配置文件里面没有这个beanName,
//如果配置文件里有那就去IOC容器里面拿就好了,不需要自动注入
//而不是采用注入的方式
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
//满足条件之后添加进里面
result.add(pd.getName());
}
}
可以看到结果,result为0
假如我们去掉配置文件的property