Spring(十四):继续创建单例Bean,提前曝光,linux基础及应用教程梁如军答案

//判断后继处理器是否已经初始化

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值