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

回到顶部