Spring IoC容器初始化源码—populateBeaninitializeBean填充Bean字段反射和setter方法依赖注入以及IoC容器初始化总结四万字
Posted 刘Java
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IoC容器初始化源码—populateBeaninitializeBean填充Bean字段反射和setter方法依赖注入以及IoC容器初始化总结四万字相关的知识,希望对你有一定的参考价值。
基于最新Spring 5.x,详细介绍了bean的“初始化过程”,主要包括applyMergedBeanDefinitionPostProcessors、populateBean、initializeBean、registerDisposableBeanIfNecessary核心方法,最后对Spring IoC容器初始化进行了总结!
上一篇文章:Spring IoC容器初始化源码(7)—createBean实例化Bean以及构造器自动注入中,我们主要讲解了ClassPathXmlApplicationContext IoC容器初始化的refresh方法中的createBean方法的全部流程以及该方法内部的createBeanInstance方法的源码——bean的创建以及基于构造器的自动注入的过程,即bean的“实例化”
。
现在我们继续向下学习refresh()方法的中的后面的内容,接下来就是bean的“初始化”过程
,主要知识点包括:applyMergedBeanDefinitionPostProcessors
方法查找解析各种回调注解或者自动注入注解、populateBean
方法填充bean实例、initializeBean
方法对bean实例进行各种回调、registerDisposableBeanIfNecessary
方法尝试注册bean销毁回调方法。最后,我们会对这几篇文章讲解的Spring IoC容器初始化源码进行简单的总结!
Spring IoC容器初始化源码 系列文章
Spring IoC容器初始化源码(1)—setConfigLocations设置容器配置信息
Spring IoC容器初始化源码(2)—prepareRefresh准备刷新、obtainFreshBeanFactory加载XML资源、解析<beans/>标签
Spring IoC容器初始化源码(3)—parseDefaultElement、parseCustomElement解析默认、扩展标签,registerBeanDefinition注册Bean定义
Spring IoC容器初始化源码(4)—<context:component-scan/>标签解析、spring.components扩展点、自定义Spring命名空间扩展点
Spring IoC容器初始化源码(5)—prepareBeanFactory、invokeBeanFactoryPostProcessors、registerBeanPostProcessors方法
Spring IoC容器初始化源码(6)—finishBeanFactoryInitialization实例化Bean的整体流程以及某些扩展点
Spring IoC容器初始化源码(7)—createBean实例化Bean的整体流程以及构造器自动注入
Spring IoC容器初始化源码(8)—populateBean、initializeBean填充Bean、字段反射和setter方法依赖注入以及IoC容器初始化总结【四万字】
< context:property-placeholder/>标签以及PropertySourcesPlaceholderConfigurer占位符解析器源码深度解析
三万字的ConfigurationClassPostProcessor配置类后处理器源码深度解析
基于JavaConfig的AnnotationConfigApplicationContext IoC容器初始化源码分析
文章目录
- Spring IoC容器初始化源码 系列文章
- 1 applyMergedBeanDefinitionPostProcessors应用MergedBeanDefinitionPostProcessor后处理器
- 1.1 CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调
- 1.2 AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调
- 1.3 ApplicationListenerDetector.postProcessMergedBeanDefinition回调
- 2 addSingletonFactory添加单例工厂
- 2 populateBean填充bean实例
- 2.1 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation回调
- 2.2 autowireByName 基于byName的setter自动注入解析
- 2.3 autowireByType基于byType的setter自动注入解析
- 2.4 InstantiationAwareBeanPostProcessor.postProcessProperties回调注解注入
- 2.5 applyPropertyValues属性setter装配
- 3 initializeBean初始化bean实例
- 4 registerDisposableBeanIfNecessary注册销毁回调
- 5 finishRefresh完成刷新
- 6 IoC容器初始化总结
我们接着上一篇文章继续向下讲doCreateBean方法在createBeanInstance之后的源码!
1 applyMergedBeanDefinitionPostProcessors应用MergedBeanDefinitionPostProcessor后处理器
createBeanInstance实例化bean完毕之后,方法或者字段依赖注入之前,会接着调用applyMergedBeanDefinitionPostProcessors方法,正如方法名那样,这个方法将会查找全部MergedBeanDefinitionPostProcessor类型的后处理器,回调它们的postProcessMergedBeanDefinition方法,该方法可以改变已合并的bean定义,当然还能做更多的事情,最常见的就是解析字段和方法上的某些注解。
很多的后处理器都是MergedBeanDefinitionPostProcessor的子类型,比如CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor、ApplicationListenerDetector这三个常见的后处理器,它们的postProcessMergedBeanDefinition方法都将在这里被依次回调,即在bean实例化之后被回调。
- CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法最开始还会调用父类InitDestroyAnnotationBeanPostProcessor的同名方法用于处理方法上的@PostConstruct、@PreDestroy注解,随后自己处理字段和方法上的@WebServiceRef、@EJB、@Resource注解。
- AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法用于处理方法和字段上的@Autowired、@Value、@Inject注解。
- ApplicationListenerDetector的postProcessMergedBeanDefinition方法用于记录ApplicationListener类型的bean是否是单例的,后面监听器过滤的时候才会用到。
注意,在这一步(applyMergedBeanDefinitionPostProcessors方法)仅仅是简单解析这些注解,相当于查找并缓存起来,后面某些时候,比如依赖注入的时候会被再次调用,到时候将进一步深度解析它们的配置属性和功能。
/**
* 将MergedBeanDefinitionPostProcessors后处理器应用于指定的 bean 定义,调用其postProcessMergedBeanDefinition方法。
*
* @param mbd 已合并的bean定义
* @param beanType bean的类型
* @param beanName beanName
*/
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
//获取、遍历全部已注册的后处理器
for (BeanPostProcessor bp : getBeanPostProcessors())
//如果bp属于MergedBeanDefinitionPostProcessor
if (bp instanceof MergedBeanDefinitionPostProcessor)
//那么强制转型
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
//回调postProcessMergedBeanDefinition方法,该方法可用于修改给定bean的已合并的RootBeanDefinition
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
1.1 CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调
该方法首先会调用父类InitDestroyAnnotationBeanPostProcessor的同名方法用于处理PostConstruct、PreDestroy注解。随后自己处理@WebServiceRef、@EJB、@Resource注解。
/**
* CommonAnnotationBeanPostProcessor的方法
* <p>
* 调用父类InitDestroyAnnotationBeanPostProcessor的同名方法用于处理:PostConstruct、PreDestroy注解。
* 随后自己处理:@WebServiceRef、@EJB、@Resource注解。
*
* @param beanDefinition 已合并的bean定义
* @param beanType bean的类型
* @param beanName beanName
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)
/*调用父类的InitDestroyAnnotationBeanPostProcessor的同名方法用于处理@PostConstruct、@PreDestroy注解*/
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
/*自己处理@WebServiceRef、@EJB、@Resource注解*/
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
//检查配置
metadata.checkConfigMembers(beanDefinition);
很多后处理器在创建的时候会初始化很多的属性,CommonAnnotationBeanPostProcessor也不例外,最重要的是它会设置父类的init 和 destroy 注解类型默认为javax.annotation.PostConstruct和javax.annotation.PreDestroy。因此我们也可以自定义初始化和销毁注解。
/**
* CommonAnnotationBeanPostProcessor的构造器
* <p>
* 设置父类的init 和 destroy 注解类型为javax.annotation.PostConstruct和javax.annotation.PreDestroy
* 因此我们也可以自定义初始化和销毁注解
*/
public CommonAnnotationBeanPostProcessor()
//设置父类InitDestroyAnnotationBeanPostProcessor的order属性
//用于排序
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
//设置父类InitDestroyAnnotationBeanPostProcessor的initAnnotationType属性
//表示初始化回调注解的类型
setInitAnnotationType(PostConstruct.class);
//设置父类InitDestroyAnnotationBeanPostProcessor的destroyAnnotationType属性
//表示销毁回调注解的类型
setDestroyAnnotationType(PreDestroy.class);
//设置自己的ignoredResourceTypes属性
//表示在解析@Resource注解时忽略给定的资源类型。
ignoreResourceType("javax.xml.ws.WebServiceContext");
1.1.1 InitDestroyAnnotationBeanPostProcessor. postProcessMergedBeanDefinition回调
内部就是调用两个方法,findLifecycleMetadata用于解析该Class,获取全部具有@PostConstruct、@PreDestroy注解的方法的LifecycleMetadata包装对象。
checkConfigMembers用于检查配置信息,主要是防止后续重复调用回调方法。
/**
* InitDestroyAnnotationBeanPostProcessor的方法
* <p>
* 处理@PostConstruct、@PreDestroy注解
*
* @param beanDefinition 已合并的bean定义
* @param beanType bean的类型
* @param beanName beanName
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)
//获取生命周期相关的元数据对象,LifecycleMetadata是该类的内部类,内部持有当前的class以及对应的具有@PostConstruct、@PreDestroy注解的方法
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
//检查配置信息
metadata.checkConfigMembers(beanDefinition);
1.1.1.1 findLifecycleMetadata处理@PostConstruct、@PreDestroy注解
用于获取该Class的LifecycleMetadata,内部保存了具有@PostConstruct、@PreDestroy注解的方法。
首先尝试从lifecycleMetadataCache缓存中获取,没有缓存就进行解析,解析之后会将结果存入缓存,后续相同的Class不再解析。
/**
* InitDestroyAnnotationBeanPostProcessor的方法
* <p>
* 获取LifecycleMetadata
*
* @param clazz bean的类型
* @return LifecycleMetadata对象,内部持有当前的class以及对应的具有@PostConstruct、@PreDestroy注解的方法
*/
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz)
//如果lifecycleMetadataCache缓存为null
if (this.lifecycleMetadataCache == null)
// 创建该类型的LifecycleMetadata
return buildLifecycleMetadata(clazz);
//否则,查询缓存
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
//如果存在该类型的缓存,从缓存获取
if (metadata == null)
synchronized (this.lifecycleMetadataCache)
//加锁之后再次获取,防止并发
metadata = this.lifecycleMetadataCache.get(clazz);
//如果metadata为null
if (metadata == null)
//那么创建该类型的LifecycleMetadata
metadata = buildLifecycleMetadata(clazz);
//存入缓存汇中
this.lifecycleMetadataCache.put(clazz, metadata);
//返回
return metadata;
//如果缓存不为null,那么直接返回缓存
return metadata;
1.1.1.1.1 buildLifecycleMetadata创建LifecycleMetadata
关键方法就是buildLifecycleMetadata方法,用于解析该Class的LifecycleMetadata。
大概逻辑是:遍历该Class及其父Class,查找具有@PostConstruct和@PreDestroy注解的方法,封装成为一个LifecycleElement对象,存入两个集合中,父类的回调方法的LifecycleElement在集合的前面,最后会根据该Class以及初始化、销毁集合创建一个LifecycleMetadata对象返回。
//------InitDestroyAnnotationBeanPostProcessor的相关属性------
/**
* 初始化回调注解的类型,默认@PostConstruct
*/
@Nullable
private Class<? extends Annotation> initAnnotationType;
/**
* 销毁回调注解的类型,默认@PreDestroy
*/
@Nullable
private Class<? extends Annotation> destroyAnnotationType;
/**
* 排序优先级
*/
private int order = Ordered.LOWEST_PRECEDENCE;
/**
1. InitDestroyAnnotationBeanPostProcessor的方法
2. <p>
3. 根据给定的类型,创建LifecycleMetadata
4. 遍历该类及其父类查找初始化注解和销毁注解
5. 6. @param clazz bean的类型
7. @return LifecycleMetadata对象,内部持有当前的class以及对应的具有@PostConstruct、@PreDestroy注解的方法
*/
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz)
//确定给定类是否是承载指定注释的候选项(在类型、方法或字段级别)。
//如果任何一个注解的全路径名都不是以"java."开始,并且该Class全路径名以"start."开始,或者Class的类型为Ordered.class,那么返回false,否则其他情况都返回true
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType)))
//如果该类型不能承载这两个主机,那么直接返回emptyLifecycleMetadata,这是一个空的LifecycleMetadata实例
return this.emptyLifecycleMetadata;
//到这里表示允许承载,那么尝试查找
//初始化回调方法集合
List<LifecycleElement> initMethods = new ArrayList<>();
//销毁回调方法集合
List<LifecycleElement> destroyMethods = new ArrayList<>();
//目标类型
Class<?> targetClass = clazz;
/*循环遍历该类及其父类,直到父类为Object*/
do
//当前的初始化回调方法集合
final List<LifecycleElement> currInitMethods = new ArrayList<>();
//当前的销毁回调方法集合
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
/*
* 循环过滤所有的方法(不包括构造器),查找被初始化注解@PostConstruct和销毁注解@PreDestroy标注的方法
* 这两个注解都是标注在方法上的,构造器上没有标注
*/
ReflectionUtils.doWithLocalMethods(targetClass, method ->
//如果initAnnotationType不为null,并且存在该类型的注解
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType))
//那么根据当前方法新建一个LifecycleElement,添加到currInitMethods中
//LifecycleElement表示了一个具有@PostConstruct、@PreDestroy等生命周期注解的方法
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled())
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
//如果initAnnotationType不为null,并且存在该类型的注解
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType))
//那么根据当前方法新建一个LifecycleElement,添加到currDestroyMethods中
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled())
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
);
//currInitMethods集合整体添加到initMethods集合的开头
initMethods.addAll(0, currInitMethods);
//currDestroyMethods集合整体添加到destroyMethods集合的开头
destroyMethods.addAll(currDestroyMethods);
//获取下一个目标类型,是当前类型的父类型
targetClass = targetClass.getSuperclass();
//如果目标类型不为null并且不是Object.class类型,那么继续循环,否则结束循环
while (targetClass != null && targetClass != Object.class);
//如果initMethods和destroyMethods都是空集合,那么返回一个空的LifecycleMetadata实例
//否则返回一个新LifecycleMetadata,包含当前的class以及对应的找到的initMethods和destroyMethods
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
1.1.1.1.2 LifecycleElement生命周期回调方法包装
LifecycleElementInit是DestroyAnnotationBeanPostProcessor的内部类,一个LifecycleElement对象封装了一个生命周期回调方法,及其标识符,标识符用于方法重复调用。
在创建LifecycleElement的时候做两件事:
- 进行参数校验,只有0个参数的方法才能作为初始化或者销毁回调方法,否则抛出异常:Lifecycle method annotation requires a no-arg method……
- 计算当前方法的identifier标识符,用于避免重复调用回调方法。如果是私有方法,则标识符为该方法的全路径名;如果是非私有方法,则标识符为该方法简单名字。
/**
* InitDestroyAnnotationBeanPostProcessor的内部类
* 一个LifecycleElement对象封装了一个回调方法,及其标识符,标识符用于方法重复调用
*/
private static class LifecycleElement
/**
* 当前方法
*/
private final Method method;
/**
* 标识符
*/
private final String identifier;
public LifecycleElement(Method method)
//如果方法参数不为0,那么抛出异常,从这里可知,初始化和销毁回调方法都不能有参数
if (method.getParameterCount() != 0)
throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
this.method = method;
//计算identifier
//如果是私有方法,则标识符为:该方法的全路径名,如果是非私有方法,则标识符为该方法简单名字
this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
ClassUtils.getQualifiedMethodName(method) : method.getName());
1.1.1.2 checkConfigMembers检查配置
设置相关的方法到checkedInitMethods和checkedDestroyMethods中,后续直接调用。同时设置到mbd的externallyManagedInitMethods中,防止重复调用同一个方法,后面会讲。
//-------LifecycleMetadata的属性----------
/**
* 目标类型
*/
private final Class<?> targetClass;
/**
* 初始化回调方法集合
*/
private final Collection<LifecycleElement> initMethods;
/**
* 销毁回调方法集合
*/
private final Collection<LifecycleElement> destroyMethods;
/**
* 检查的初始化回调方法集合
*/
@Nullable
private volatile Set<LifecycleElement> checkedInitMethods;
/**
* 检查的销毁回调方法集合
*/
@Nullable
private volatile Set<LifecycleElement> checkedDestroyMethods;
/**
* LifecycleMetadata的构造器
* @param targetClass 目标类型
* @param initMethods 初始化回调方法
* @param destroyMethods 销毁回调方法
*/
public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods,
Collection<LifecycleElement> destroyMethods)
//为属性赋值
this.targetClass = targetClass;
this.initMethods = initMethods;
this.destroyMethods = destroyMethods;
/**
* LifecycleMetadata的方法
*
* 检查配置,设置相关的方法到checkedInitMethods和checkedDestroyMethods中,后续直接调用
* 同时设置到mbd的externallyManagedInitMethods中,防止重复调用同一个方法
* @param beanDefinition 当前bean定义
*/
public void checkConfigMembers(RootBeanDefinition beanDefinition)
//创建被检查的初始化回调方法集合
Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
//遍历检查initMethods
for (LifecycleElement element : this.initMethods)
//获取标识符
String methodIdentifier = element.getIdentifier();
//如果mbd的externallyManagedInitMethods不包含当前回调方法
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier))
//设置到mbd的externallyManagedInitMethods中
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
//设置到checkedInitMethods中
checkedInitMethods.add(element);
if (logger.isTraceEnabled())
logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + element);
Set<LifecycleElement> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size());
for (LifecycleElement element : this.destroyMethods)
//获取标识符
String methodIdentifier = element.getIdentifier();
//如果mbd的externallyManagedInitMethods不包含当前回调方法
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier))
//设置到mbd的externallyManagedInitMethods中以上是关于Spring IoC容器初始化源码—populateBeaninitializeBean填充Bean字段反射和setter方法依赖注入以及IoC容器初始化总结四万字的主要内容,如果未能解决你的问题,请参考以下文章