Spring源码分析容器刷新提取依赖注入元数据与实现注入
今天无意中发现自己还没有把“applyMergedBeanDefinitionPostProcessors”的作用搞清楚,抽点时间把这部分源码再看一遍,顺便将自动注入概要讲一下。
这两个功能都是在同一个核心方法里面,先贴出来核心方法的大体逻辑
protectedObjectdoCreateBean(finalStringbeanName, finalRootBeanDefinitionmbd, final@NullableObject[] args)throwsBeanCreationException {
。。。省略部分代码。。。
if (instanceWrapper==null) {
//创建裸对象
instanceWrapper=createBeanInstance(beanName, mbd, args);
}
。。。省略部分代码。。。
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//提取JSR-250 JSR-330 和Spring 关于依赖注入注解的元数据
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
。。。省略部分代码。。。
}
}
/**
* 立即缓存起来以解决循环依赖的问题,earlySingletonObjects
* 如果存在循环依赖,则isSingletonCurrentlyInCreation循环依赖的beanName会被添加到singletonsCurrentlyInCreation集合中
*/
booleanearlySingletonExposure= (mbd.isSingleton() &&this.allowCircularReferences&&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean ""+beanName+
"" to allow for resolving potential circular references");
}
//SingletonFactory的getObject()方法再获取对象的时候才会被调用,这行代码只是把SingletonFactory放到对应的集合当中
addSingletonFactory(beanName, () ->getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
ObjectexposedObject=bean;
try {
//根据BeanDefinition中给定的相关参数,使用AutowiredAnnotationBeanPostProcessor填充BeanWrapper中的Bean Instance,包括自动注入对象(@Autowired)和属性(@Value)
populateBean(beanName, mbd, instanceWrapper);
/**
* 1.BeforeInitialization调用BeanPostProcessor
* 2.调用initMethod
* 3.BeforeInitialization调用BeanPostProcessor
*/
exposedObject=initializeBean(beanName, exposedObject, mbd);
}
。。。省略部分代码。。。
//如果Bean有destroy方法,如果Bean是单例,则将其添加到DefaultListableBeanFactory.disposableBeans当中,否则添加到Scope的相关属性中
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
。。。省略部分代码。。。
returnexposedObject;
}
本篇没有非常详细描述Spring创建Bean的所有过程,重点描述提取元数据和如何使用元数据完成依赖注入,更多细节请看源码中的注释
提取元数据
概述
调用CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor分别提取JSR-250和Spring的注入相关元数据并保存到集合中,当进行属性操作(注入)时就根据两个PostProcessor中的该BeanNamed对应的元数据信息完成自动注入。
详解
经过Debug发现,方法里面有三个PostProcessor会被调用,它们完成了JSR-250和Spring自带注解的提取与保存功能,下面分别对三个PostProcessor进行分析。
CommonAnnotationBeanPostProcessor
概述:将符合JSR-250的相关注解元数据提取出来并添加到RootBeanDefinition当中相关属性中
publicvoidpostProcessMergedBeanDefinition(RootBeanDefinitionbeanDefinition, Class<?>beanType, StringbeanName) {//提取JSR-250中initMethod和destroyMethod并添加到BeanDefinition的externallyManagedInitMethod和externallyManagedDestroyMethod当中
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
//找JSR-250中@Resource @WebServiceRef @EJB 注解修饰的元数据
InjectionMetadatametadata=findResourceMetadata(beanName, beanType, null);
//将上一步找到的元数据添加到BeanDefinition中的externallyManagedConfigMember
metadata.checkConfigMembers(beanDefinition);
}
每个方法点进去的注解,请下载源码查看
下面看看CommonAnnotationBeanPostProcessor和RootBeanDefinition属性截图
@Resource注解被提取并添加到CommonAnnotationBeanPostProcessor.injectionMetadataCache中
注:injectionMetadataCache是CommonAnnotationBeanPostProcessor私有的
Spring在后面会根据key=testIDBean中cache中找到元数据,循环所有的injectedElements,完成依赖注入
@Resource、@PostConstruct、@PreDestroy注解被提取并添加到RootBeanDefinition中
注:RootBeanDefinition在Spring中是共享的
AutowiredAnnotationBeanPostProcessor
提取注解@Autowired、@Value、@Inject修饰的元数据
publicvoidpostProcessMergedBeanDefinition(RootBeanDefinitionbeanDefinition, Class<?>beanType, StringbeanName) {//找到自动注入的元数据@Autowired @Value @Inject(JSR-330)
InjectionMetadatametadata=findAutowiringMetadata(beanName, beanType, null);
//检验一遍上一步得到的元数据是否是真的要进行注入的
metadata.checkConfigMembers(beanDefinition);
}
和CommonAnnotationBeanPostProcessor相比少了一个super.postProcessMergedBeanDefinition,代码非常相似。
@Autowired、@Value、@Inject注解被提取并添加到CommonAnnotationBeanPostProcessor.injectionMetadataCache中
注:injectionMetadataCache是CommonAnnotationBeanPostProcessor私有的
Spring在后面会根据key=testIDBean中cache中找到元数据,循环所有的injectedElements,完成依赖注入
@Autowired、@Value、@Inject注解被提取并添加到RootBeanDefinition中,这里只会涉及到externallyManagedConfigMembers,另外两个只有JSR-250中的@PostConstruct和@PreDestroy会用到
注:RootBeanDefinition在Spring中是共享的
ApplicationListenerDetector
这个干的事情非常简单,往它的singletoneName添加每一个beanName
publicvoidpostProcessMergedBeanDefinition(RootBeanDefinitionbeanDefinition, Class<?>beanType, StringbeanName) {this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
依赖注入
就是从前面提到的缓存(injectionMetadataCache)中拿元数据完成自动注入
先截个图证明执行完下面的代码完成了自动注入
populateBean(beanName, mbd, instanceWrapper);
下面进到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法中,有这么一段代码,它们完成了自动注入
for (BeanPostProcessorbp : getBeanPostProcessors()) {if (bpinstanceofInstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessoribp= (InstantiationAwareBeanPostProcessor) bp;
// -----------------比如对象和属性值的注入------------------------
PropertyValuespvsToUse=ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse==null) {
。。。省略部分代码。。。//这里是老版本Spring的注入,Spring5.1就标记为过期了
}
pvs=pvsToUse;
}
}
这段代码重点看各个PostProcessor的postProcessProperties方法,以下是对几个被调用PostProcessor的详细分析
ConfigurationClassPostProcessor
很简单,如果当前的Bean是一个增强的配置类EnhancedConfiguration(它是一个接口,继承自BeanFactoryAware)就给把DefaultListableBeanFactory实例给它
CommonAnnotationBeanPostProcessor
从缓存中拿到@Resource修饰属性的元数据,完成自动注入
publicPropertyValuespostProcessProperties(PropertyValuespvs, Objectbean, StringbeanName) {//从this.injectionMetadataCache中找出ResourceMetadata
InjectionMetadatametadata=findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//完成注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwableex) {
thrownewBeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
returnpvs;
}
从缓存中拿到的元数据截图,需要注入使用@Resource修饰的BeanProperty
因为要被注入的对象在实例化testIDBean之前就完成了,所以看不到“注入时如果被注入Bean还未实例化,先实例化它的情况”,但是在AutowiredAnnotationPostProcessor可以看到,因为User此时还未实例化
AutowiredAnnotationBeanPostProcessor
从缓存中拿@Autowired @Value @Inject修饰属性的元数据并完成自动注入
publicPropertyValuespostProcessProperties(PropertyValuespvs, Objectbean, StringbeanName) {/**
* 这里的数据从哪里来的???答案是applyMergedBeanDefinitionPostProcessors使用
* CommonAnnotationBeanPostProcessor提取了JSR-250的注解:@Resource
* AutowiredAnnotationPostProcessor提取了Spring带的注解:@Autowired
* 它们提出来的要被注入的对象和被注入的属性放入到this.injectionMetadataCache
*/
InjectionMetadatametadata=findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationExceptionex) {
throwex;
}
catch (Throwableex) {
thrownewBeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
returnpvs;
}
从缓存中拿到的元数据截图,需要注入使用@Autowired修饰的User
当Debug模式下执行如下代码
metadata.inject(bean, beanName, pvs);
那么就会开始Spring创建Bean的完成流程,看截图
在populateBean放中最后还有一段设置属性的代码
if (pvs!=null) {/**
* 从BeanDefinition的propertyValues当中属性名和带有setXxx的方法匹配,并设置值
* 注:感觉平时开发很少用到,因为没有提供什么直接的注解往propertyValues中添加值,在Mybatis整合Spring的时候看到用过
* 为了测试写了一个PVBeanFactoryPostProcessor,手动强制更改某一个类的BeanDefinition.propertyValues
*/
applyPropertyValues(beanName, mbd, bw, pvs);
}
以上是 Spring源码分析容器刷新提取依赖注入元数据与实现注入 的全部内容, 来源链接: utcz.com/z/513095.html