基于最新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中
beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
//设置到checkedInitMethods中
checkedDestroyMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
//为这两个缓存赋值
this.checkedInitMethods = checkedInitMethods;
this.checkedDestroyMethods = checkedDestroyMethods;
}
1.1.2. findResourceMetadata处理@WebServiceRef、@EJB、@Resource注解
findResourceMetadata方法是CommonAnnotationBeanPostProcessor的方法,用于处理方法或者字段上的@WebServiceRef、@EJB、@Resource注解。
首先尝试从injectionMetadataCache缓存中获取,没有缓存就进行解析,解析之后会将结果存入缓存,后续相同的Class不再解析。
/**
* 注入点元数据缓存
*/
private final transient Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
/**
1. CommonAnnotationBeanPostProcessor的方法
2. <p>
3. 获取注入点ResourceMetadata元数据,具有@WebServiceRef、@EJB、@Resource注解
4. 5. @param beanName beanName
6. @param clazz Class
7. @param pvs null
8. @return InjectionMetadata对象
*/
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
//获取缓存key,如果beanName为null或"",那么使用类名
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
//尝试从缓存中获取
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//如果缓存为null,或者需要刷新,那么解析
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
//加锁之后再次获取,防止并发
metadata = this.injectionMetadataCache.get(cacheKey);
//如果缓存为null,或者需要刷新,那么解析
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//创建该类型的ResourceMetadata
metadata = buildResourceMetadata(clazz);
//存入缓存
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
1.1.2.1 buildResourceMetadata获取InjectionMetadata
关键方法就是buildResourceMetadata方法,用于解析该Class的ResourceMetadata,实际类型为InjectionMetadata,内部保存了具有@WebServiceRef、@EJB、@Resource注解的字段或者方法。
大概逻辑是:遍历该Class及其父Class,依次查找具有@WebServiceRef、@EJB、@Resource注解的字段和方法,封装成为一个WebServiceRefElement、EjbRefElement、ResourceElement对象,存入一个注入点资源集合中,父类中的注入点资源信息在集合的前面,最后会根据该Class以及注入点资源集合初始化一个InjectionMetadata对象返回。
注意:
- 在当前字段或者方法上依次查找@WebServiceRef、@EJB、@Resource注解,只要找到一个注解,该字段或者方法就会被封装成为对应的Element,后续的注解不再查找,类似于“短路法”。
- 如果@WebServiceRef、@EJB、@Resource注解用在字段上,那么该字段不能是静态的;
- 如果@WebServiceRef、@EJB、@Resource注解用在方法上,那么该方法不能是静态的,并且有且具有唯一一个参数。
//---------CommonAnnotationBeanPostProcessor的相关属性
/**
* 资源注释类型集合
*/
private static final Set<Class<? extends Annotation>> resourceAnnotationTypes = new LinkedHashSet<>(4);
/**
* WebServiceRef注解类型
*/
@Nullable
private static final Class<? extends Annotation> webServiceRefClass;
/**
* EJB注解类型
*/
@Nullable
private static final Class<? extends Annotation> ejbClass;
/**
* 忽略资源类型的集合,注意是名字的集合
*/
private final Set<String> ignoredResourceTypes = new HashSet<>(1);
/*
* 静态块,添加资源注解类型
*/
static {
//尝试加载@WebServiceRef和@EJB资源注解的Class
webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
ejbClass = loadAnnotationType("javax.ejb.EJB");
//依次添加javax.annotation.Resource、WebServiceRef、EJB注解的Class到resourceAnnotationTypes缓存中,如果存在
resourceAnnotationTypes.add(Resource.class);
if (webServiceRefClass != null) {
resourceAnnotationTypes.add(webServiceRefClass);
}
if (ejbClass != null) {
resourceAnnotationTypes.add(ejbClass);
}
}
/**
* CommonAnnotationBeanPostProcessor的方法
* <p>
* 创建ResourceMetadata,实际类型为InjectionMetadata
*
* @param clazz bean的类型
* @return InjectionMetadata对象,内部持有注入点注解标注的注入点
*/
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
//确定给定类是否是承载指定注释的候选项(在类型、方法或字段级别)。
//如果任何一个注解的全路径名都不是以"java."开始,并且该Class全路径名以"start."开始,或者Class的类型为Ordered.class,那么返回false,否则其他情况都返回true
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
//如果不满足,那么直接返回空InjectionMetadata对象
return InjectionMetadata.EMPTY;
}
//存储资源注入点的InjectedElement对象集合
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
//目标类型
Class<?> targetClass = clazz;
/*循环遍历该类及其父类,直到父类为Object或者null*/
do {
//当前Class的资源注入点的InjectedElement对象集合
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
/*
* 1 循环过滤所有的字段,查找被资源注解(@WebServiceRef、@EJB、@Resource)标注的字段注入点
*/
ReflectionUtils.doWithLocalFields(targetClass, field -> {
/*如果webServiceRefClass不为null,并且该字段上存在@WebServiceRef的注解*/
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
//如果字段是静态的,抛出异常
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
//那么根据当前字段新建一个WebServiceRefElement,添加到currElements中
//WebServiceRefElement表示了一个具有@WebServiceRef注解的字段
currElements.add(new WebServiceRefElement(field, field, null));
}
/*否则,如果ejbClass不为null,并且该字段上存在@EJB的注解*/
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
//如果字段是静态的,抛出异常
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
//那么根据当前字段新建一个EjbRefElement,添加到currElements中
//EjbRefElement表示了一个具有@EJB注解的字段
currElements.add(new EjbRefElement(field, field, null));
}
/*否则,如果该字段上存在@Resource的注解*/
else if (field.isAnnotationPresent(Resource.class)) {
//如果字段是静态的,抛出异常
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
//如果当前字段的类型的名字不在ignoredResourceTypes中,那么根据当前字段新建一个ResourceElement,添加到currElements中
//EjbRefElement表示了一个具有@Resource注解且不被忽略的字段
//这里可以知道,如果不想注入某一类型对象 可以通过ignoreResourceType方法将其加入ignoredResourceTypes中
// 默认加入了"javax.xml.ws.WebServiceContext",该类型字段需要运行时注入
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
/*
* 2 循环过滤所有的方法(不包括构造器),查找被资源注解(@WebServiceRef、@EJB、@Resource)标注的方法
* 这几个注解一般都是标注在字段、方法、类上的,构造器上没有标注
*/
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//查找原始方法而非编译器为我们生成的方法
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//如果当前方法重写了父类的方法,则使用子类的
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
/*如果webServiceRefClass不为null,并且该方法上存在@WebServiceRef的注解*/
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
//如果方法是静态的,抛出异常
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
//如果方法参数不是一个,抛出异常
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
//查找方法参数
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//那么根据当前方法和参数新建一个WebServiceRefElement,添加到currElements中
//WebServiceRefElement表示了一个具有@WebServiceRef注解的方法
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
/*否则,如果ejbClass不为null,并且该方法上存在@EJB的注解*/
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
//如果方法是静态的,抛出异常
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
//如果方法参数不是一个,抛出异常
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
//查找方法参数
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//那么根据当前方法和参数新建一个EjbRefElement,添加到currElements中
//EjbRefElement表示了一个具有@EJB注解的方法
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
/*否则,如果该方法上存在@Resource的注解*/
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
//如果方法是静态的,抛出异常
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
//如果方法参数不是一个,抛出异常
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
//如果当前方法的参数类型的名字不在ignoredResourceTypes中,那么根据当前字段新建一个ResourceElement,添加到currElements中
//EjbRefElement表示了一个具有@Resource注解且不被忽略的字段
//这里可以知道,如果不想注入某一类型对象 可以通过ignoreResourceType方法将其加入ignoredResourceTypes中
// 默认加入了"javax.xml.ws.WebServiceContext",该类型字段需要运行时注入
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
//currElements集合整体添加到elements集合的开头,即父类的资源注解在前面
elements.addAll(0, currElements);
//获取下一个目标类型,是当前类型的父类型
targetClass = targetClass.getSuperclass();
}
//如果目标类型不为null并且不是Object.class类型,那么继续循环,否则结束循环
while (targetClass != null && targetClass != Object.class);
//根据找到的elements和Class创建InjectionMetadata对象,如果没有任何注入点元素,那么返回一个空的InjectionMetadata
return InjectionMetadata.forElements(elements, clazz);
}
/**
* InjectionMetadata的方法
*
* @param elements 资源注入点元素集合,可能是一个方法或者字段
* @param clazz 目标类型
* @return 新的InjectionMetadata注入点元数据对象,如果没有任何注入点元素,那么返回一个空的InjectionMetadata
*/
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
}
1.1.2.2 checkConfigMembers检查配置
设置相关的注入点到checkedElements中,后续直接调用。如果此前mbd的externallyManagedConfigMembers中没有某个注入点的信息,那么该注入点就加入到externallyManagedConfigMembers以及checkedElements中,否则该注入点将可能不被调用。
主要目的是在后续解析这些注入点进行依赖注入时,防止重复调用同一个注入点进行没必要的重复注入,比如一个字段上同时具有@Resource和@Autowired注解,那么最后将使用@Resource注解进行注入而不是@Autowired。
//-------InjectionMetadata的属性----------
/**
* 目标类型
*/
private final Class<?> targetClass;
/**
* 找到的注入点资源集合
*/
private final Collection<InjectedElement> injectedElements;
/**
* 检查的注入点资源集合
*/
@Nullable
private volatile Set<InjectedElement> checkedElements;
/**
* InjectionMetadata的构造器
*/
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
this.targetClass = targetClass;
this.injectedElements = elements;
}
/**
* InjectionMetadata的方法
*
* @param beanDefinition 当前bean定义
*/
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
//新建checkedElements集合
Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
//遍历injectedElements集合
for (InjectedElement element : this.injectedElements) {
//获取标识符信息
Member member = element.getMember();
//如果mbd的externallyManagedConfigMembers不包含当前注入点信息
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
//设置到mbd的externallyManagedConfigMembers中
beanDefinition.registerExternallyManagedConfigMember(member);
//设置到checkedElements中
checkedElements.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
//为这个缓存赋值
this.checkedElements = checkedElements;
}
1.2 AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition回调
在AutowiredAnnotationBeanPostProcessor初始化的时候,一般的自动注入注解的类型@Autowired、@Value、@Inject(必须有JSR-330的API)就按照顺序被加入到AutowiredAnnotationBeanPostProcessor内部的autowiredAnnotationTypes缓存中了。
/**
* AutowiredAnnotationBeanPostProcessor的属性
* <p>
* 自动注入的注解类型集合
*/
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
/**
* AutowiredAnnotationBeanPostProcessor的构造器
* <p>
* 将@Autowired和@Value注解的类型存入autowiredAnnotationTypes集合,同时支持JSR-330的@Inject(如果存在)
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
//按照顺序添加@Autowired、@Value、@javax.inject.Inject注解的类Class到autowiredAnnotationTypes集合中
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
} catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
postProcessMergedBeanDefinition方法用于处理具有@Autowired、@Value、@Inject注解标注的字段或者方法。
内部就是调用findAutowiringMetadata和checkConfigMembers两个方法。
这里的checkConfigMembers方法的逻辑和CommonAnnotationBeanPostProcessor的同名方法的逻辑是一样的,都是存入externallyManagedConfigMembers缓存。因为实际上它们都是用于依赖注入的注解,因此如果此前就存在针对该注入点的自动注入注解的解析数据缓存则后面的同一个注入点的其他自动注入注解的解析数据不会被存入。
比如,一个字段上同时存在@Resource和@Autowired两个注解,那么由于注解解析顺序为@Resource > @Autowired,解析@Autowired时,由于externallyManagedConfigMembers已存在该类型的ResourceElement缓存,因此@Autowired注解的AutowiredFieldElement不会被存入,最重要的是也不会存入checkedElements,后续inject方法回调的时候就是使用checkedElements中的元素来进行调用,因此将使用@Resource注解进行依赖注入而不是@Autowired。
如果某一个字段、方法、参数上有多个依赖注入的注解,那么这些注解并不会都进行解析、注入,它们具有优先级,依赖注入注解的使用优先级为:@WebServiceRef > @EJB > @Resource > @Autowired > @Value > @Inject。
/**
* AutowiredAnnotationBeanPostProcessor的方法
* <p>
* 处理具有@Autowired、@Value、@Inject注解标注的字段或者方法
*
* @param beanDefinition 已合并的bean定义
* @param beanType bean的类型
* @param beanName beanName
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//处理自动注入注解@Autowired、@Value、@Inject,返回自动注入点的InjectionMetadata元数据对象
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
//检查配置,和CommonAnnotationBeanPostProcessor的同名方法具有一样的逻辑
metadata.checkConfigMembers(beanDefinition);
}
1.2.1 findAutowiringMetadata处理@Autowired、@Value、@Inject注解
用于处理方法或者字段上的@Autowired、@Value、@Inject注解。首先尝试从injectionMetadataCache缓存中获取,没有缓存就进行解析,解析之后会将结果存入缓存,后续相同的Class不再解析。
/**
* 查找给定类型上的自动注入注解@Autowired、@Value、@Inject
*
* @param beanName beanName
* @param clazz Class
* @param pvs null
* @return InjectionMetadata对象,内部持有自动注入注解标注的注入点
*/
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
//获取缓存key,如果beanName为null或"",那么使用类名
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
//尝试从缓存中获取
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//如果缓存为null,或者需要刷新,那么解析
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
//加锁之后再次获取,防止并发
metadata = this.injectionMetadataCache.get(cacheKey);
//如果缓存为null,或者需要刷新,那么解析
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//创建该类型的AutowiringMetadata
metadata = buildAutowiringMetadata(clazz);
//存入缓存
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
1.2.1.1 buildAutowiringMetadata获取InjectionMetadata
关键方法就是buildAutowiringMetadata方法,用于解析该Class的ResourceMetadata,实际类型为InjectionMetadata,内部保存了具有@Autowired、@Value、@Inject注解的字段或者方法。
大概逻辑是:遍历该Class及其父Class,依次查找具有@Autowired、@Value、@Inject注解的字段和方法,封装成为一个AutowiredFieldElement或者AutowiredMethodElement对象,存入一个自动注入点集合中,父类中的自动注入点信息在集合的前面,最后会根据该Class以及自动注入点集合初始化一个InjectionMetadata对象返回。
注意:
- 在当前字段或者方法上依次查找@Autowired、@Value、@Inject注解,只要找到一个注解,该字段或者方法就会被封装成为对应的Element,后续的注解不再查找。
- 如果@Autowired、@Value、@Inject注解用在字段上,那么该字段不能是静态的;
- 如果@Autowired、@Value、@Inject注解用在方法上,那么该方法不能是静态的,并且具有至少一个参数。
/**
* AutowiredAnnotationBeanPostProcessor的方法
* <p>
* 创建AutowiringMetadata,实际类型为InjectionMetadata
*
* @param clazz bean的类型
* @return InjectionMetadata对象,内部持有自动注入注解@Autowired、@Value、@Inject标注的注入点
*/
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
//确定给定类是否是承载指定注释的候选项(在类型、方法或字段级别)。
//如果任何一个注解的全路径名都不是以"java."开始,并且该Class全路径名以"start."开始,或者Class的类型为Ordered.class,那么返回false,否则其他情况都返回true
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
//如果不满足,那么直接返回空InjectionMetadata对象
return InjectionMetadata.EMPTY;
}
//存储自动注入点的InjectedElement对象集合
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
//目标类型
Class<?> targetClass = clazz;
/*循环遍历该类及其父类,直到父类为Object或者null*/
do {
//当前Class的自动注入点的InjectedElement对象集合
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
/*
* 1 循环过滤所有的字段,查找被自动注入注解(@Autowired、@Value、@Inject)标注的字段注入点
* 这三个注解都可以标注在字段上
*/
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//findAutowiredAnnotation用于查找自动注入注解,在前在determineCandidateConstructors部分就讲过了
//按照顺序查找,只要找到一个自动注入注解就返回,因此优先级@Autowired > @Value > @Inject
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
//如果存在自动注入注解
if (ann != null) {
//如果字段是静态的,抛出异常
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
//判断是否是必须的,即是否是@Inject、@Value注解,或者是@Autowired注解并且required属性为true
boolean required = determineRequiredStatus(ann);
//那么根据当前字段field和required新建一个AutowiredFieldElement,添加到currElements中
//AutowiredFieldElement表示了一个具有自动注入注解的字段
currElements.add(new AutowiredFieldElement(field, required));
}
});
/*
* 2 循环过滤所有的方法(不包括构造器),查找被自动注入注解(@Autowired、@Value、@Inject)标注的方法和构造器注入点
* 注意,标注在参数上是无效的
*/
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//查找原始方法而非编译器为我们生成的方法,方法不可见就直接返回
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//findAutowiredAnnotation用于查找自动注入注解,在前在determineCandidateConstructors部分就讲过了
//按照顺序查找,只要找到一个自动注入注解就返回,因此优先级@Autowired > @Value > @Inject
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//如果方法是静态的,抛出异常
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
//如果方法参数个数为0,抛出异常
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
//判断是否是必须的,即是否是@Inject、@Value注解,或者是@Autowired注解并且required属性为true
boolean required = determineRequiredStatus(ann);
//查找方法参数
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//那么根据当前方法method和required和参数新建一个AutowiredMethodElement,添加到currElements中
//AutowiredMethodElement表示了一个具有自动注入注解的方法
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
//currElements集合整体添加到elements集合的开头,即父类的自动注入注解的注入点在前面
elements.addAll(0, currElements);
//获取下一个目标类型,是当前类型的父类型
targetClass = targetClass.getSuperclass();
}
//如果目标类型不为null并且不是Object.class类型,那么继续循环,否则结束循环
while (targetClass != null && targetClass != Object.class);
//根据找到的elements和Class创建InjectionMetadata对象,如果没有任何注入点元素,那么返回一个空的InjectionMetadata
return InjectionMetadata.forElements(elements, clazz);
}
1.3 ApplicationListenerDetector.postProcessMergedBeanDefinition回调
用于记录ApplicationListener类型的bean是否是单例的,后面监听器过滤的时候才会用到,不必关心。
/**
* ApplicationListenerDetector的属性
*/
private final transient Map<String, Boolean> singletonNames = new ConcurrentHashMap<>(256);
/**
* ApplicationListenerDetector的方法
* <p>
* 用于记录ApplicationListener类型的bean是否是单例的,后面监听器过滤的时候才会用到
*
* @param beanDefinition 已合并的bean定义
* @param beanType bean的类型
* @param beanName beanName
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//如果当前bean类型为ApplicationListener,即是一个监听器
if (ApplicationListener.class.isAssignableFrom(beanType)) {
//存入singletonNames缓存中,key为beanName,value为该bean是否是"singleton"单例的
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
2 addSingletonFactory添加单例工厂
将早期单例实例工厂存入singletonFactories缓存中,用于解决循环依赖。
如果A依赖B、B依赖A,那么依赖注入的时候,将会注入一个从singletonFactories中的ObjectFactory获取的早期对象。为什么叫"早期"呢?因为此时该实例虽然被创建,但是可能还没有执行后续的依赖注入(setter方法、注解反射)的过程,该bean实例是不完整的,但是此时能够保证获取的依赖不为null而不会抛出异常,并且和后续进行的注入对象是同一个对象,从而在不知不觉中解决循环依赖。
以前的版本第二个参数传递的是一个ObjectFactory的匿名对象,Spring5以及Java8的之后第二个参数传递的是一个lambda对象,lambda语法更加简单,采用invokedynamic指令运行时动态构建类,不会生成额外的class文件,这个lambda的意思就是:ObjectFactory对象的getObject方法实际上就是调用这里的getEarlyBeanReference方法。
/**
* DefaultSingletonBeanRegistry的方法
* <p>
* 如有必要,添加给定的单例工厂到singletonFactories缓存中,以生成指定的单例,以期望解决循环引用
* <p>
*
* @param beanName beanName
* @param singletonFactory 单例对象的工厂
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
//同步
synchronized (this.singletonObjects) {
//如果单例对象缓存中不存在该beanName的实例
if (!this.singletonObjects.containsKey(beanName)) {
//那么将当前beanName作为key,当前ObjectFactory的lambda对象作为value存入singletonFactories缓存
this.singletonFactories.put(beanName, singletonFactory);
//从earlySingletonObjects移除该名字的缓存
this.earlySingletonObjects.remove(beanName);
//加入registeredSingletons缓存
this.registeredSingletons.add(beanName);
}
}
}
2.1 getEarlyBeanReference回调SmartInstantiationAwareBeanPostProcessor获取早期bean引用
singletonFactories中的lambda的ObjectFactory对象的getObject方法被调用的时候,实际上就是调用这里的getEarlyBeanReference方法。
该方法应用全部SmartInstantiationAwareBeanPostProcessor类型后处理器的getEarlyBeanReference方法,该方法可以改变要返回的提前暴露的单例bean引用对象,获取用于早期访问的bean 的引用,只有单例bean会调用该方法。默认使用最后一个应用的方法的返回值作为最终结果。
SmartInstantiationAwareBeanPostProcessor接口的getEarlyBeanReference方法是一个默认方法,其实现为直接返回传递的参数bean实例,对于Spring基础核心依赖来说,它的实现类也都是默认返回传递的参数bean实例,也就是说Spring在这个扩展点方法中没有任何额外操作,但是我们可以自定义后处理器,重写该方法定义自己的逻辑。
但是如果我们引入了spring-aop的依赖,那么这个依赖包中的AbstractAutoProxyCreator后处理器则重写了该方法,用于对早期bean引用创建并返回代理对象,这个方法非常重要,可以解决通过AbstractAutoProxyCreator创建的AOP代理对象之间的循环依赖,比如普通的自定义Spring AOP代理以及Spring声明式事务的代理,但是Spring异步任务则是通过AbstractAdvisingBeanPostProcessor来实现代理的,因此可能出现循环依赖异常,这一点我们后面会介绍。
/**
* AbstractAutowireCapableBeanFactory的方法
* <p>
* 应用SmartInstantiationAwareBeanPostProcessor后处理器的getEarlyBeanReference方法
* 该方法可以改变要返回的提前暴露的单例bean引用对象
* 获取用于早期访问的bean 的引用,通常用于解析循环引用,只有单例bean会调用该方法
*
* @param beanName bean的名称(用于错误处理目的)
* @param mbd bean的合并bean定义
* @param bean 原始bean实例
* @return 要公开为 bean 引用的对象
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
//exposedObject赋值为参数bean对象
Object exposedObject = bean;
//如果当前bean定义不是合成的,并且具有InstantiationAwareBeanPostProcessor这个类型的后处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//获取、遍历全部注册的后处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果属于SmartInstantiationAwareBeanPostProcessor类型
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
//强转
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
//回调getEarlyBeanReference方法,传递的参数就是此前获取的bean实例以及beanName
//该方法可以改变要返回的提前暴露的单例bean引用对象,默认直接返回参数bean实例
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
/**
* SmartInstantiationAwareBeanPostProcessor接口的默认方法
*/
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
//返回参数bean实例
return bean;
}
/**
* 子类InstantiationAwareBeanPostProcessorAdapter的重写的方法
*/
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
//返回参数bean实例
return bean;
}
2 populateBean填充bean实例
使用 bean 定义中的属性值在给定的 BeanWrapper 中填充 bean 实例,简单的说就是:setter方法和注解反射方式的依赖注入,有可能由于依赖其他bean而导致其他bean的初始化。
同样这也是一个核心方法。前面的createBeanInstance操作被称为"实例化"bean操作,简单的说就调用构造器创建对象,这里的操作就是"初始化"bean的操作,分为两步,populateBean和initializeBean。populateBean简单的说就是对bean实例进行依赖注入,即属性“填充”,initializeBean则是进行各种方法的回调,比如初始化方法回调。
populateBean方法可以完成:
- 基于XML配置的< property/>标签的setter方法注入;
- 基于XML的byType和byName的setter方法自动注入;
- 基于注解的setter方法和属性反射自动注入。
/**
1. AbstractAutowireCapableBeanFactory的方法
2. <p>
3. 使用 bean 定义中的属性值在给定的 BeanWrapper 中填充 bean 实例,简单的说就是:
4. setter方法和注解反射方式的依赖注入,有可能由于依赖其他bean而导致其他bean的初始化
5. 6. @param beanName beanName
7. @param mbd bean的bean定义
8. @param bw 具有 Bean 实例的BeanWrapper对象
*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
/*
* 1 校验bw为null的情况
* 如果此bean定义中定义了<property>标签,那么抛出异常,其他情况则直接返回
*/
//如果bw为null
if (bw == null) {
//如果mbd存在propertyValues属性,即定义了<property>标签
//因为BeanWrapper都为null了,不能进行依赖注入,那么抛出异常
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
} else {
//跳过null实例的属性装配阶段
return;
}
}
/*
* 2 在bean实例化之后,属性填充(初始化)之前,回调InstantiationAwareBeanPostProcessor后处理器的
* postProcessAfterInstantiation方法,可用于修改bean实例的状态
*
* Spring在这个扩展点方法中没有任何额外操作,但是我们可以自定义后处理器,重写该方法定义自己的逻辑。
*/
// 确保mbd不是合成的,并且具有InstantiationAwareBeanPostProcessor这个后处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//遍历所有注册的BeanPostProcessor后处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果属于InstantiationAwareBeanPostProcessor类型
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//强制转型
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//回调postProcessAfterInstantiation方法,传递的参数就是此前获取的bean实例以及beanName
//该方法可用于在bean实例化之后,初始化之前,修改bean实例的状态
//如果返回false,则不会继续应用后续的处理同时也会结束后续的属性填充流程,该方法结束,否则继续向后调用
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
//获取bean定义的PropertyValues集合,在此前的parsePropertyElement方法中,我们说过
//所有的<property>标签标签都被解析为PropertyValue对象并存入PropertyValues集合中了
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
/*
* 3 根据名称或者类型进行setter自动注入,适用于基于XML的配置autowire自动注入,现在很少基于XML配置了
* 并没有真正的注入,而是将可以自动注入的属性名和bean实例存入新建的newPvs中,后面会统一注入
*/
//获取已解析的自动注入模式,默认就是0,即不自动注入,可以设置,对应XML的autowire属性
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
//如果是1(就是byName),或者如果是2(就是byType),单纯使用注解注入就是0
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//根据原来的属性新建一个属性集合
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 基于byName的setter自动注入
//并没有真正的注入,而是将可以自动注入的属性名和bean实例存入新建的newPvs中,后面会统一注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 基于byType的setter自动注入
//并没有真正的注入,而是将可以自动注入的属性名和bean实例存入新建的newPvs中,后面会统一注入
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
//pvs赋值为newPvs
//现在pvs中包括了我们定义的<property>标签属性,以及找到的byName和byType的setter自动注入属性
pvs = newPvs;
}
//是否具有InstantiationAwareBeanPostProcessor这个后处理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//是否需要进行依赖检查,即是否设置dependencyCheck属性,表示属性强制检查,就是XML的dependency-check属性
//然而这个属性早在spring3.0的时候就被废弃了,代替它的就是构造器注入或者@Required,默认就是0,不进行强制检查,因此为false
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
/*
* 4 查找全部InstantiationAwareBeanPostProcessor后处理器,回调postProcessProperties方法
* 解析此前通过applyMergedBeanDefinitionPostProcessors方法找到的自动注入注解,这里进行了注解的真正的注入
*/
if (hasInstAwareBpps) {
//如果为null,初始化一个空的MutablePropertyValues对象
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//获取、遍历全部注册的后处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果属于SmartInstantiationAwareBeanPostProcessor类型
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//强转
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
/*
* 回调postProcessProperties方法,传递的参数就是目前的pvs、bean实例、beanName,解析、注入此前通过
* applyMergedBeanDefinitionPostProcessors方法找到的自动注入注解,返回PropertyValues
*
* CommonAnnotationBeanPostProcessor -> 解析注入@WebServiceRef、@EJB、@Resource注解,默认直接返回参数pvs
* AutowiredAnnotationBeanPostProcessor -> 解析注入@Autowired、@Value、@Inject注解,默认直接返回参数pvs
*
* 在Spring 5.1 之前使用的是postProcessPropertyValues回调方法,Spring 5.1开始该方法被不推荐使用,推荐使用postProcessProperties来替代
*/
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
//如果pvsToUse为null,那么调用此前的已被放弃的postProcessPropertyValues方法继续尝试
if (pvsToUse == null) {
//获取属性描述符
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//调用postProcessPropertyValues方法,该方法已被丢弃
//实际上CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor的方法内部就是直接调用的postProcessProperties方法
//只有RequiredAnnotationBeanPostProcessor有自己的逻辑,但是我们知道RequiredAnnotationBeanPostProcessor已经整体丢弃了
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
//还是返回null,那什么直接结束这个方法
if (pvsToUse == null) {
return;
}
}
//从新设置pvs,对于CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor来说具有同一批数据
pvs = pvsToUse;
}
}
}
//如果需要进行依赖检查,默认不需要,Spring3.0之后没法设置设置
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
/*
* 5 如果pvs不为null,这里默认的pvs就是<property>标签和byName或者byType找到的属性值的汇总
* 这里将所有PropertyValues中的属性继续填充到bean实例中
*/
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
2.1 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation回调
在bean实例化之后,属性填充(初始化)之前,回调InstantiationAwareBeanPostProcessor后处理器的postProcessAfterInstantiation方法,用于自定义初始化bean实例以及是否继续填充属性。如果返回false,则不会继续应用后续的处理同时也会结束后续的属性填充流程,finishBeanFactoryInitialization方法结束,否则继续向后调用。
目前Spring的全部后处理器的实现在这个扩展点方法postProcessAfterInstantiation中没有任何额外操作,都是直接返回true,但是我们可以自定义后处理器,重写该方法定义自己的逻辑。
// 确保mbd不是合成的,并且具有InstantiationAwareBeanPostProcessor这个后处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//遍历所有注册的BeanPostProcessor后处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果属于InstantiationAwareBeanPostProcessor类型
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//强制转型
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//回调postProcessAfterInstantiation方法,传递的参数就是此前获取的bean实例以及beanName
//该方法可用于在bean实例化之后,初始化之前,修改bean实例的状态
//如果返回false,则不会继续应用后续的InstantiationAwareBeanPostProcessor,否则继续向后调用
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
2.2 autowireByName 基于byName的setter自动注入解析
基于byName的setter自动注入解析,但实际上并没有真正的注入,而是将可以自动注入的属性名和bean实例存入新建的newPvs中,后面会统一注入。这个方法实际上是为基于XML的配置autowire=byName的自动注入服务的,但是现在很少基于XML配置了。
- 调用unsatisfiedNonSimpleProperties用于获取需要进行注入的非简单类型的属性名数组。
- 随后遍历该数组,在当前工厂以及父工厂中查找以该属性名作为beanName的bean实例或者bean定义:
- 如果存在:
- 那么获取该bean的实例,随后将该属性名以及对应的bean实例存入newPvs集合中。
- 这些被自动注入的bean也算作当前bean定义依赖的bean,因此,类似于createArgumentArray方法最后的逻辑,将propertyName和beanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中。表示beanName的实例依赖propertyName的实例,这个方法我们在前面就讲过了。
- 如果不存在,那么放弃该setter方法自动注入,不会抛出异常。
- 如果存在:
/**
1. AbstractAutowireCapableBeanFactory的方法
2. <p>
3. 通过"byName"引用此工厂中的其他 bean 实例填充缺失的属性,将属性名和bean实例存入newPvs集合中
4. 并没有真正的注入依赖,类似于预先查找
5. 6. @param beanName 需要进行自动注入的beanName
7. @param mbd bean定义
8. @param bw BeanWrapper
9. @param pvs XML注册的property属性
*/
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//获取需要自动依赖注入的"属性名"数组,实际上是查找的setter方法
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//遍历属性名数组
for (String propertyName : propertyNames) {
/*
* 如果此 Bean 工厂及其父工厂包含具有给定名称的 bean 定义或bean实例
*/
if (containsBean(propertyName)) {
//调用getBean通过propertyName获取bean实例,这里就有可能初始化该beanName的实例
Object bean = getBean(propertyName);
//将propertyName和bean实例加入到pvs集合中
pvs.add(propertyName, bean);
//那么将propertyName和beanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中
//表示beanName的实例依赖propertyName的实例,这个方法我们在前面就讲过了
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");
}
}
}
}
2.2.1 unsatisfiedNonSimpleProperties获取需要进行注入的非简单类型的“属性”名数组
unsatisfiedNonSimpleProperties用于获取需要进行注入的非简单类型的“属性”名数组。
byName自动注入实际上是通过setter方法注入的,它和真正的所谓的字段属性无关,实际上,这里的“属性”也是从setter方法中获取的(后面注解的setter方法注入也是这个逻辑)。
大概步骤为:
- 查找该bean所属的类中每一个具有一个参数的setter方法封装为PropertyDescriptor属性描述符对象:
- 截取方法名的"set"之后的部分,并进行处理:如果至少开头两个字符是大写,那么就返回原截取的值,否则返回开头为小写的截取的值。处理之后的字符串之后作为PropertyDescriptor的name属性。
- 方法的参数类型作为PropertyDescriptor的propertyType属性。
- 然后对每一个PropertyDescriptor进行校验:
- 如果该描述符存在用于写属性的方法(即"set"开头的方法)。
- 并且没有排除依赖类型检查:该propertyType类型没有在ignoredDependencyTypes忽略注入集合中,该方法所属的类的类型没有在ignoredDependencyInterfaces忽略注入集合中。此前讲的忽略setter自动注入的扩展点就是这两个集合的控制的,这里就知道它的使用原理了。可以通过ignoreDependencyType和ignoreDependencyInterface方法设置。
- 并且自己定义的property的集合没有该"属性名",即所有的< property>标签的name属性不包括该"属性"的name。因为如果我们定义了该名字的< property>标签,那么将会注入定义的标签的值,而不会自动查找其他依赖。
- 并且propertyType不是简单类型属性:基本类型及其包装类、Enum、String、CharSequence、Number、Date、Temporal、URI、URL、Locale、Class等这些类型的单个对象或者数组都被称为简单类型。
- 满足一起上四个条件,则将“属性”名加入到一个临时集合中,遍历完毕返回该集合。
/**
1. AbstractAutowireCapableBeanFactory的方法
2. <p>
3. 获取需要进行自动依赖注入的非简单 bean 属性名称数组,排除简单类型的属性,实际上是查找的setter方法
4. 5. @param mbd bean定义
6. @param bw BeanWrapper
7. @return bean 属性名称数组
*/
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
//获取自己定义的property的集合
PropertyValues pvs = mbd.getPropertyValues();
//获取BeanWrapper中的属性描述符数组。
//请注意,这里的一个数组元素实际上是一个具有一个参数的setter方法转换之后的属性描述符
//PropertyDescriptor的name属性是截取的"set"之后的部分,并进行了处理:如果至少开头两个字符是大写,那么就返回原截取的值,否则返回开头为小写的截取的值
//PropertyDescriptor的propertyType属性是方法的参数类型
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
//遍历数组
for (PropertyDescriptor pd : pds) {
//1 如果该描述符存在用于写属性的方法(即"set"开头的方法)
//2 并且没有排除依赖类型检查(该类型没有在ignoredDependencyTypes和ignoredDependencyInterfaces两个忽略注入的集合中
// 此前讲的忽略setter自动注入的扩展点就是这两个集合的控制的,可以通过ignoreDependencyType和ignoreDependencyInterface方法设置)
//3 并且自己定义的property的集合没有该"属性名",即所有的<property>标签的name属性不包括该"属性"的name
//4 并且propertyType不是简单类型属性:基本类型及其包装类、Enum、String、CharSequence、Number、Date、Temporal、URI、URL、Locale、Class
// 这些类型的单个对象或者数组都被称为简单类型。
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
//将name添加到返回值集合中
result.add(pd.getName());
}
}
//转换为数组并返回
return StringUtils.toStringArray(result);
}
2.3 autowireByType基于byType的setter自动注入解析
基于byType的setter自动注入解析,但实际上并没有真正的注入,而是将可以自动注入的属性名和bean实例存入新建的newPvs中,后面会统一注入。这个方法实际上是为基于XML的配置autowire=byType的自动注入服务的,但是现在很少基于XML配置了。
- 调用unsatisfiedNonSimpleProperties用于获取需要进行注入的非简单类型的属性名数组。
- 随后遍历该数组:
- 根据获取对应的AutowireByTypeDependencyDescriptor对象,它的required的属性为false,表示非必需依赖。
- 调用resolveDependency方法根据参数类型解析依赖,这个方法在前面已经讲过了,但是之前的required的属性都是true,这里的required的属性为false,因此查找的规则还是有些区别:
- 如果没找到任何依赖就返回null,不会抛出异常。
- 如果找到多个同类型依赖项并且没找到最合适的依赖则依然会抛出异常(除非是集合类型依赖),这里的规则是一样的。
- 区别于基于XML的构造器自动注入和基于注解的构造器、setter方法、属性反射注入,这里在最后不会根据参数名匹配beanName去查找。从名字能看出来,仅仅是byType而已,因此一定要注意。
- resolveDependency方法不返回null,那么将propertyName和返回的autowiredArgument数据(可能是个集合)加入到pvs集合中。如果返回null,那么放弃注入。
- 遍历自动注入的beanName,这些bean也算作当前bean定义依赖的bean,类似于createArgumentArray方法最后的逻辑,将autowiredBeanName和beanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中。
/**
* AbstractAutowireCapableBeanFactory的方法
* <p>
* 通过"byType"引用此工厂中的其他 bean 实例填充缺失的属性,将属性名和bean实例存入newPvs集合中
* 并没有真正的注入依赖,类似于预先查找
*
* @param beanName 需要进行自动注入的beanName
* @param mbd bean定义
* @param bw BeanWrapper
* @param pvs 已找到的property属性
*/
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//获取AbstractBeanFactory中的typeConverter自定义类型转换器属性,该属性用来覆盖默认属性编辑器PropertyEditor
//并没有提供getCustomTypeConverter方法的默认返回,因此customConverter默认返回null,我们同样可以自己扩展
TypeConverter converter = getCustomTypeConverter();
//如果没有自定义类型转换器就是用当前bw
if (converter == null) {
converter = bw;
}
//自动注入的beanName集合
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//获取需要自动依赖注入的"属性名"数组,实际上是查找的setter方法
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//遍历属性名数组
for (String propertyName : propertyNames) {
try {
//获取PropertyDescriptor
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
//如果参数类型不是Object类型,永远不会按照类型自动注入任何属于Object类型的属性
if (Object.class != pd.getPropertyType()) {
//获取方法参数对象,必须是setter方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// bean实例是否不属于PriorityOrdered类型
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
//根据方法参数和eager创建一个AutowireByTypeDependencyDescriptor依赖描述符对象
//前面说过这表示一个依赖注入点的信息,注意,使用这个构造器创建的对象的required的属性为false
//即非必须依赖,即如果没有找到该类型的依赖也不会抛出异常,而是返回null
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
//调用resolveDependency方法根据类型解析依赖,这个方法在前面已经讲过了
//如果没找到任何依赖就返回null,如果找到多个同类型依赖项并且没找到最合适的依赖则会抛出异常(除非是集合类型依赖)
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
//如果不为null,将propertyName和bean实例加入到pvs集合中,如果为null,那么放弃注入
if (autowiredArgument != null) {
//
pvs.add(propertyName, autowiredArgument);
}
/*
* 遍历自动注入的beanName,这些bean也算作当前bean定义依赖的bean
* 这就类似于createArgumentArray方法最后的逻辑了
*/
for (String autowiredBeanName : autowiredBeanNames) {
//那么将autowiredBeanName和beanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中
//这个方法我们在前面就讲过了
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
//清空autowiredBeanNames集合
autowiredBeanNames.clear();
}
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
2.4 InstantiationAwareBeanPostProcessor.postProcessProperties回调注解注入
前面的autowireByName和autowireByType的setter自动注入解析实际上是为XML的配置服务的,如果采用注解配置,那么这两个步骤都不走,无论是@Resource还是@Autowired,注解的AutowireMode都是AUTOWIRE_NO。并且,这两步并没有真正的注入,后面会统一注入。
在上一步查找完毕之后,马上会遍历全部InstantiationAwareBeanPostProcessor后处理器,回调postProcessProperties方法,解析此前通过applyMergedBeanDefinitionPostProcessors方法找到的自动注入注解。这里就是为注解的配置服务的。对于注解的解析和注入会在这一步同时完成。
重写了该方法的InstantiationAwareBeanPostProcessor接口的常见实现就是CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor,这就与applyMergedBeanDefinitionPostProcessors方法中解析的后处理器对上了。
CommonAnnotationBeanPostProcessor的实现:
/**
* CommonAnnotationBeanPostProcessor的方法
* <p>
* 进一步解析@WebServiceRef、@EJB、@Resource注解,执行自动注入
*
* @param pvs 已找到的属性值数组
* @param bean bean实例
* @param beanName beanName
* @return 要应用于给定 bean 的实际属性值(可以是传递的pvs),或为null(为了兼容原方法,随后会调用postProcessPropertyValues查找)
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//熟悉的findResourceMetadata方法,用于处理方法或者字段上的@WebServiceRef、@EJB、@Resource注解
//前面的applyMergedBeanDefinitionPostProcessors中已被解析了,因此这里直接从缓存中获取
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//调用metadata的inject方法完成注解注入
metadata.inject(bean, beanName, pvs);
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
//返回pvs,即原参数
return pvs;
}
AutowiredAnnotationBeanPostProcessor的实现:
/**
* AutowiredAnnotationBeanPostProcessor的方法
* <p>
* 进一步解析@Autowired、@Value、@Inject注解,执行自动注入
*
* @param pvs 已找到的属性值数组
* @param bean bean实例
* @param beanName beanName
* @return 要应用于给定 bean 的实际属性值(可以是传递的pvs),或为null(为了兼容原方法,随后会调用postProcessPropertyValues查找)
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//熟悉的findResourceMetadata方法,用于处理方法或者字段上的@Autowired、@Value、@Inject注解
//前面的applyMergedBeanDefinitionPostProcessors中已被解析了,因此这里直接从缓存中获取
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//调用metadata的inject方法完成注解注入
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
//返回pvs,即原参数
return pvs;
}
可以看到,它们的逻辑都差不多,首先就是从缓存获取此前已被解析了的InjectionMetadata对象,随后调用metadata的inject方法完成注解注入,返回pvs,即原参数。
可见,关键方法就是inject方法!
2.4.1 InjectionMetadata.inject注解注入
对于Metadata内部的全部InjectedElement执行注解注入,内部的InjectedElement还是调用了自己的同名inject方法。
AutowiredFieldElement、AutowiredMethodElement这两个类型均重写了该方法,其它类型的Element实现则使用父类InjectedElement本身的方法
/**
* InjectionMetadata的方法
* <p>
* 对于Metadata内部的全部InjectedElement执行注解注入
*
* @param target 需要进行注入的目标实例
* @param beanName 当前beanName
* @param pvs 已找到的属性值数组,用于防止重复注入
*/
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//如果checkedElements不为null,那么就使用checkedElements,即已检查的注解,前面就说过了,这用于防止注解重复注入
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
//遍历每一个InjectedElement,一个InjectedElement就表示一个注入点,可能是字段或者方法
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
//调用各种类型的element的inject方法完成每一个注入点的注入操作
//AutowiredFieldElement、AutowiredMethodElement这两个类型均重写了该方法,其它类型则使用父类InjectedElement本身的方法
element.inject(target, beanName, pvs);
}
}
}
2.4.2 InjectedElement.inject执行@WebServiceRef、@EJB、@Resource注解解析注入
InjectionMetadata的内部类InjectedElement本身的inject方法用于执行@WebServiceRef、@EJB、@Resource注解的解析和注入。
对于字段和方法类型的注入点,都是反射调用字段和方法进行注入的。在方法注入点进行解析和注入之前,会先检查是否可以跳过该方法的"属性"注入,也就是看此前找到的pvs中是否存在该名字的属性,如果存在就跳过,不存在就不跳过。因此setter方法的注入流程的优先级为:XML手动设置的property > XML设置自动注入的找到的property -> 注解设置的property。只有在前面的流程中没找到指定名称的property时,当前流程才会查找property。
/**
* InjectionMetadata的内部类InjectedElement本身的方法
*
* 完成每一个注入点的注入操作,包括@WebServiceRef、@EJB、@Resource注解的解析
*
* @param target 需要进行注入的目标实例
* @param requestingBeanName beanName
* @param pvs 已找到的属性值数组,用于防止重复注入
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
/*
* 如果是字段属性注入点
*/
if (this.isField) {
//获取字段
Field field = (Field) this.member;
//设置字段的可访问属性,即field.setAccessible(true)
ReflectionUtils.makeAccessible(field);
/*
* 1 反射注入该字段属性的值,getResourceToInject方法默认返回null,
* 该方法被WebServiceRefElement、EjbRefElement、ResourceElement
* 这几个子类重写,用于获取要注入的属性值,我们主要看ResourceElement重写的方法
*/
field.set(target, getResourceToInject(target, requestingBeanName));
}
/*否则,表示一个方法注入点*/
else {
/*
* 2 检查是否可以跳过该"属性"注入,也就是看此前找到的pvs中是否存在该名字的属性,如果存在就跳过,不存在就不跳过
* 这里可以发现:
* setter方法的注入流程的优先级为:XML手动设置的property > XML设置自动注入的找到的property -> 注解设置的property
* 前面的流程中没找到指定名称的property时,当前流程才会查找property
*/
if (checkPropertySkipping(pvs)) {
return;
}
try {
//获取方法
Method method = (Method) this.member;
//设置方法的可访问属性,即field.setAccessible(true)
ReflectionUtils.makeAccessible(method);
/*
* 3 反射调用该方法,设置参数的值,getResourceToInject方法默认返回null,
* 该方法被WebServiceRefElement、EjbRefElement、ResourceElement
* 这几个子类重写,用于获取要注入的属性值,我们主要看ResourceElement重写的方法
*/
method.invoke(target, getResourceToInject(target, requestingBeanName));
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
获取需要注入的依赖的核心方法是getResourceToInject,该方法同样被WebServiceRefElement、EjbRefElement、ResourceElement这几个子类重写,我们主要看ResourceElement重写的方法,也就是如何解析@Resource注解的!
2.4.2.1 @Resource注解的基本解析
注意,@Resource注解的各种属性基本能解析实际上在ResourceElement的构造器中就完成了!
需要注意的点:
- name属性表示依赖项的名字:
- 首先是获取@Resource注解设置的name属性,作为name;
- 如果没有设置name属性,对于字段注入点来说默认name就是:属性名;对于方法注入点来说默认name就是:截取setter方法名的"set"之后的部分,并进行处理:如果至少开头两个字符是大写,那么就返回原截取的值,否则返回开头为小写的截取的值。
- lookupType属性表示依赖项的类型:
- 首先是获取@Resource注解设置的type属性,作为类型;
- 如果设置了type属性,那么校验指定的type如果和字段类型或者方法参数类型不兼容,那么抛出异常。
- 如果没有设置type属性,对于字段注入点来说默认type就是:属性类型;对于方法注入点来说默认type就是:参数类型。
- lazyLookup表示是否返回一个代理依赖对象:
- 如果存在@Lazy注解并且值为true,那么lazyLookup为true,否则就是false。
- @WebServiceRef、@EJB、@Resource注解注解的依赖描述符类型为LookupDependencyDescriptor,且required属性为true。
/**
* CommonAnnotationBeanPostProcessor的内部类
* 表示注解字段或 setter 方法的注入信息的类,支持@Resource注解。
*/
private class ResourceElement extends LookupElement {
/**
* 是否需要返回代理依赖对象
*/
private final boolean lazyLookup;
/**
* 构造器,在applyMergedBeanDefinitionPostProcessors方法中被调用,用来创建@Resource注解相关对象
*
* @param member 字段或者方法
* @param ae 字段或者方法
* @param pd 构造器传递null
*/
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
//调用父类LookupElement的构造器
super(member, pd);
//获取@LookupElement注解
Resource resource = ae.getAnnotation(Resource.class);
//获取name属性值,如果没设置,那么默认返回""
String resourceName = resource.name();
//获取type属性,如果没设置,那么默认返回Object.class
Class<?> resourceType = resource.type();
//是否没有设置name属性,如果没设置,那么isDefaultName=true
this.isDefaultName = !StringUtils.hasLength(resourceName);
/*如果没设置了name属性,使用自己的规则作为name*/
if (this.isDefaultName) {
//获取属性名或者方法名
resourceName = this.member.getName();
//如果是setter方法,并且长度大于3个字符
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
//那么截取setter方法名的"set"之后的部分,并进行处理:如果至少开头两个字符是大写,那么就返回原截取的值,否则返回开头为小写的截取的值
resourceName = Introspector.decapitalize(resourceName.substring(3));
}
}
/*如果设置了name属性,那么解析name属性值*/
else if (embeddedValueResolver != null) {
//这里就是解析name值中的占位符的逻辑,将占位符替换为属性值
//因此设置的name属性支持占位符,即${.. : ..},占位符的语法和解析之前就学过了,这里的占位符支持普通方式从外部配置文件中加载进来的属性以及environment的属性
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
/*如果type不是Object类型,那么检查指定的type*/
if (Object.class != resourceType) {
//如果指定type和字段类型或者方法参数类型不兼容,那么抛出异常
checkResourceType(resourceType);
} else {
//如果是,那么获取字段类型或者方法参数类型作为type
resourceType = getResourceType();
}
//设置为name属性为resourceName
this.name = (resourceName != null ? resourceName : "");
//设置lookupType属性为resourceType
this.lookupType = resourceType;
//获取注解上的lookup属性值,如果没设置,那么默认返回"",一般没人设置
String lookupValue = resource.lookup();
//如果没有设置,那么设置mappedName属性值为mappedName属性值,否则设置为lookupValue的值
this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
//尝试获取@Lazy注解
Lazy lazy = ae.getAnnotation(Lazy.class);
//如果存在@Lazy注解并且值为true,那么lazyLookup为true,否则就是false,这表示是否返回一个代理的依赖
this.lazyLookup = (lazy != null && lazy.value());
}
}
/**
* CommonAnnotationBeanPostProcessor的内部类
* <p>
* 表示注解字段或 setter 方法的注入信息的类,支持@WebServiceRef、@EJB、@Resource注解。
*/
protected abstract static class LookupElement extends InjectionMetadata.InjectedElement {
/**
* 依赖name
*/
protected String name = "";
/**
* 是否没有设置name属性
*/
protected boolean isDefaultName = false;
/**
* 依赖类型
*/
protected Class<?> lookupType = Object.class;
@Nullable
protected String mappedName;
public LookupElement(Member member, @Nullable PropertyDescriptor pd) {
//调用父类InjectionMetadata的构造器
super(member, pd);
}
/**
* 为基础字段/方法生成依赖性描述符,使用了member和lookupType
*
* lookupType首先取指定的type属性指定的类型,没有则取属性或者参数的类型
* LookupDependencyDescriptor的required属性为true
*/
public final DependencyDescriptor getDependencyDescriptor() {
if (this.isField) {
return new LookupDependencyDescriptor((Field) this.member, this.lookupType);
} else {
return new LookupDependencyDescriptor((Method) this.member, this.lookupType);
}
}
}
/**
* InjectionMetadata的内部类
* <p>
* 单个注入元素
*/
public abstract static class InjectedElement {
protected final Member member;
/**
* 是否是字段
*/
protected final boolean isField;
@Nullable
protected final PropertyDescriptor pd;
protected InjectedElement(Member member, @Nullable PropertyDescriptor pd) {
this.member = member;
this.isField = (member instanceof Field);
this.pd = pd;
}
}
2.4.2.2 ResourceElement. getResourceToInject解析@Resource获取资源用于注入
如果有@Lazy注解,则走buildLazyResourceProxy的逻辑,创建一个代理对象返回。因此,一般都是走getResource的逻辑。
/**
* ResourceElement重写的方法
*
* @param target 目标实例
* @param requestingBeanName 当前beanName
* @return 要注入的值
*/
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
//一般都是走getResource的逻辑,如果有@Lazy注解,则走buildLazyResourceProxy的逻辑,创建一个代理对象返回
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
2.4.2.2.1 getResource获取给定名称和类型的资源对象
位于CommonAnnotationBeanPostProcessor的方法,用于获取给定名称和类型的资源对象。核心方法还是autowireResource方法。
/**
1. CommonAnnotationBeanPostProcessor的方法
2. <p>
3. 获取给定名称和类型的资源对象
4. 5. @param element 注解的字段/方法的描述符
6. @param requestingBeanName 当前beanName
7. @return 资源对象(从不为null)
*/
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
//这是lockup或者mappedName属性,一般没人设置
if (StringUtils.hasLength(element.mappedName)) {
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
}
//设置使用使用Jndi注入,默认false
if (this.alwaysUseJndiLookup) {
return this.jndiFactory.getBean(element.name, element.lookupType);
}
//resourceFactory一般不为null,就是当前的工厂DefaultListableBeanFactory
if (this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property");
}
//通用逻辑就是autowireResource方法
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
2.4.2.2.2.1 autowireResource获取自动注入的资源
通过基于给定工厂的获取给定名称和类型的资源对象。该方法是@Resource注解进行资源查找的的核心方法,从这里能够知道完整的查找逻辑。
- 将name属性作为要查找的依赖名称beanName,这里的name规则在前面“@Resource注解的基本解析”部分已经讲了:
- 首先是获取@Resource注解设置的name属性,作为name;
- 如果没有设置name属性,对于字段注入点来说默认name就是:属性名;对于方法注入点来说默认name就是:截取setter方法名的"set"之后的部分,并进行处理:如果至少开头两个字符是大写,那么就返回原截取的值,否则返回开头为小写的截取的值。
- byType的情况:
- 如果fallbackToDefaultTypeMatch属性为true,默认就是true,可以通过setFallbackToDefaultTypeMatch方法修改。该属性表示如果未指定名称,是否退回到根据type查找。
- 并且,如果isDefaultName属性为true,这表示没有设置@Resource注解的name属性;
- 并且,如果此 Bean 工厂及其父工厂不包含具有给定依赖名称的 bean 定义或bean实例
- 这三个条件都满足,那么根据type查找。调用resolveDependency方法根据类型解析依赖,返回找到的依赖,查找规则在之前就讲过了,注意这里的required=true。如果没找到就抛出异常。
- byName的情况:
- 如果fallbackToDefaultTypeMatch为false,或者手动设置了name,或者存在工厂或父工厂中存在该name的bean定义或者实例,那么根据name查找,即只要byType三个条件有一个不满足,就是用byName。
- 调用resolveBeanByName方法根据name查找,如果设置了type属性,那么还必须匹配设置的type属性。内部实际上就是调用的getBean方法。
从这里我们能完整的知道@Resource注入的逻辑,byName优先于byType的原理也能从代码中看出来。如果手动设置了name,那么一定走byName的逻辑。
/**
* CommonAnnotationBeanPostProcessor的方法
* <p>
* 通过基于给定工厂的获取给定名称和类型的资源对象。
*
* @param factory 工厂
* @param element 注解的字段/方法的描述符
* @param requestingBeanName 当前beanName
* @return 资源对象(从为null)
*/
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
//自动注入的beanName集合
Set<String> autowiredBeanNames;
/*
* 获取属性名,此前创建ResourceElement对象时就已处理过了
*/
String name = element.name;
//DefaultListableBeanFactory属于AutowireCapableBeanFactory类型
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
//获取依赖描述符(可能是字段或者方法),实际类型为LookupDependencyDescriptor,它的required属性为true
DependencyDescriptor descriptor = element.getDependencyDescriptor();
/*
* 如果fallbackToDefaultTypeMatch属性为true,默认就是true,表示如果未指定名称是否退回到根据type查找
* 并且,如果isDefaultName属性为true,这表示没有设置@Resource注解的name属性,将会根据type查找
* 并且,如果此 Bean 工厂及其父工厂不包含具有给定名称的 bean 定义或bean实例,将会根据type查找
*
* 这三个条件都满足,那么根据type查找
*/
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
//调用resolveDependency方法根据类型解析依赖,返回找到的依赖,查找规则在之前讲过,注意这里的required=true
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
//如果返回null,表示没找到依赖项,那么抛出异常
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
/*
* 否则,如果fallbackToDefaultTypeMatch为false,或者设置了name属性,或者存在该name的bean或者,那么根据name查找
* 这三个条件满足一个,那么根据name查找
*/
else {
//根据name查找,如果设置了type属性,那么还必须比配设置的type属性
//内部实际上就是调用的getBean方法
resource = beanFactory.resolveBeanByName(name, descriptor);
//返回一个单个元素的集合
autowiredBeanNames = Collections.singleton(name);
}
} else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
/*遍历自动注入的beanName,这些bean也算作当前bean定义依赖的bean*/
for (String autowiredBeanName : autowiredBeanNames) {
if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
//那么将autowiredBeanName和requestingBeanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中
//这个方法我们在前面就讲过了
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
//返回resource,即找到的依赖对象
return resource;
}
/**
* 通过name解析bean,实际上还会匹配类型
*/
@Override
public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
//调用了getBean方法,传递了两个参数name和type,实际上就是ResourceElement的name和lookupType属性
//这表示找到的依赖需要满足这两个条件
return getBean(name, descriptor.getDependencyType());
} finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
2.4.2.3. checkPropertySkipping跳过属性
检查由于指定了显式属性值,是否需要跳过注入此属性。如果此前通过< property/>标签以及byName或者byType的方法找到的注入项值集合中包含当前的“属性”,那么就跳过,防止重复注入。这里能看出来,XML的配置的注入或者XML的自动注入优先于注解配置的注入。
/**
* InjectedElement的方法
* <p>
* 检查由于指定了显式属性值,是否需要跳过注入此属性。还将受影响的属性标记为已处理,供其他处理器忽略它。
* @param pvs 此前通过<property/>标签以及byName或者byType找到的注入项值,防止重复注入
*/
protected boolean checkPropertySkipping(@Nullable PropertyValues pvs) {
//skip属性
Boolean skip = this.skip;
//如果skip不为null,那么返回该值
if (skip != null) {
return skip;
}
//如果pvs为null,那么设置为false,并返回false,表示不跳过
if (pvs == null) {
this.skip = false;
return false;
}
//加同步
synchronized (pvs) {
//如果skip不为null,那么返回该值
skip = this.skip;
if (skip != null) {
return skip;
}
//如果pd不为null,在创建注入点对象时,对于字段来说为null,对于setter方法来说不为null
//因为只有setter方法会出现重复注入,因为此前找到的pvs的注入项都是setter方法注入
if (this.pd != null) {
//如果包含name,表示此前已经找到了这个setter方法
if (pvs.contains(this.pd.getName())) {
//设置skip为true,返回true,可跳过
this.skip = true;
return true;
}
//否则如果是MutablePropertyValues
else if (pvs instanceof MutablePropertyValues) {
//标记为已处理
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
}
}
//设置为false,返回false,不可跳过
this.skip = false;
return false;
}
}
2.4.3 AutowiredFieldElement.inject执行@Autowired、@Value、@Inject字段注解解析注入
InjectedElement的子类AutowiredFieldElement重写的inject方法用于执行字段上的@Autowired、@Value、@Inject注解的解析和注入。
从这里我们能完整的知道@Autowired注入的逻辑, byType优先于byName的原理也能从代码中看出来,那就是resolveDependency方法,这个方法此前我们就详细介绍过了。
另外,这里还有一个缓存的逻辑,只要经过了第一次解析,那么就会设置缓存,其中就有ShortcutDependencyDescriptor的应用,这就和doResolveDependency方法的开头调用resolveShortcut方法快速获取依赖的逻辑联系起来了(见上一篇文章)!
/**
* AutowiredAnnotationBeanPostProcessor的内部类
*
* 表示自动注入注解(@Autowired、@Value、@Inject)字段的注入信息的类。
*/
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
/**
* 是否是必须依赖
*/
private final boolean required;
/**
* 是否以缓存,即该注入点是否已被解析过
*/
private volatile boolean cached = false;
/**
* 缓存的已被解析的字段值,可能是DependencyDescriptor或者ShortcutDependencyDescriptor或者null
*/
@Nullable
private volatile Object cachedFieldValue;
/**
* 构造器
*
* @param field 字段
* @param required 是否是必须依赖
*/
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
/**
* InjectedElement的子类内部类AutowiredFieldElement重写的方法
* <p>
* 完成字段注入点的注入操作,包括@Autowired、@Value、@Inject注解的解析
*
* @param bean 需要进行注入的目标实例
* @param beanName beanName
* @param pvs 已找到的属性值数组,用于防止重复注入
*/
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//获取字段
Field field = (Field) this.member;
Object value;
//如果已被缓存过,只要调用过一次该方法,那么cached将被设置为true,后续都走resolvedCachedArgument
if (this.cached) {
//从缓存中获取需要注入的依赖
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
} else {
//获取字段描述符,这里的required属性就是@Autowired注解的required属性值,没有就设置默认true
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
//自动注入的beanName
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
//获取转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
/*
* 调用resolveDependency方法根据类型解析依赖,返回找到的依赖,查找规则在之前讲过,注意这里的required是可以设置的
* 如果required设置为false,那么没找到依赖将不会抛出异常
* 如果找到多个依赖,那么会尝试查找最合适的依赖,就掉调用determineAutowireCandidate方法,此前就讲过了
* 在最后一步会尝试根据name进行匹配,如果还是不能筛选出合适的依赖,那么抛出异常
* 这就是byType优先于byName的原理,实际上一个resolveDependency方法就完成了
*/
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
/*同步,设置缓存*/
synchronized (this) {
//如果没有被缓存,那么尝试将解析结果加入缓存
if (!this.cached) {
//如果找到了依赖,或者该依赖是必须的
if (value != null || this.required) {
//为该缓存赋值
this.cachedFieldValue = desc;
//那么将每一个autowiredBeanName和beanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中
//表示beanName的实例依赖autowiredBeanName的实例,这个方法我们在前面就讲过了
registerDependentBeans(beanName, autowiredBeanNames);
//如果只有一个bean,如果字段属性是集合则可能有多个
if (autowiredBeanNames.size() == 1) {
//获取name
String autowiredBeanName = autowiredBeanNames.iterator().next();
//如果工厂中包含该bean并且类型匹配
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
/*
* 将当前desc描述符、beanName、字段类型存入一个ShortcutDependencyDescriptor对象中,随后赋给cachedFieldValue
* 后续查找时将直接获取就有该beanName和字段类型的依赖实例返回
*/
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
} else {
//如果value为null并且不是必须依赖,那么清空缓存
//下一次走resolvedCachedArgument方法时,直接返回null
this.cachedFieldValue = null;
}
//cached设置为true,表示已解析过,并且设置了缓存
this.cached = true;
}
}
}
//如果value不为null
if (value != null) {
//设置字段的可访问属性,即field.setAccessible(true)
ReflectionUtils.makeAccessible(field);
/*
* 反射注入该字段属性的值
*/
field.set(bean, value);
}
}
}
/**
* AutowiredAnnotationBeanPostProcessor的方法
* <p>
* 解析指定的缓存方法参数或字段值
*
* @param beanName beanName
* @param cachedArgument 缓存的cachedFieldValue
*/
@Nullable
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
//如果cachedArgument不为null
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
Assert.state(this.beanFactory != null, "No BeanFactory available");
/*
* 调用resolveDependency方法根据类型解析依赖,返回找到的依赖
*
* 这里的descriptor是此前cachedFieldValue缓存起来的,如果是ShortcutDependencyDescriptor类型,那么
* 在resolveDependency方法内部的doResolveDependency方法开头就会尝试调用resolveShortcut方法快速获取依赖,
* 而这个方法在DependencyDescriptor中默认返回null,而ShortcutDependencyDescriptor则重写了该方法,
* 从给定工厂中快速获取具有指定beanName和type的bean实例。因此,上面的ShortcutDependencyDescriptor用于快速获取依赖项
*/
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
} else {
//直接返回cachedArgument,当第一次调用的value为null并且不是必须依赖,那么缓存的cachedFieldValue也置空null
//没有找到依赖又不是必须的,那么直接返回null就行了,同样是提升效率
return cachedArgument;
}
}
/**
* AutowiredAnnotationBeanPostProcessor的内部类
*/
private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
/**
* 缓存的beanName
*/
private final String shortcut;
/**
* 缓存的type
*/
private final Class<?> requiredType;
/**
* 构造器
*/
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
super(original);
this.shortcut = shortcut;
this.requiredType = requiredType;
}
/**
* 重写了resolveShortcut方法
* <p>
* 从给定工厂中快速获取具有指定beanName和type的bean实例
* <p>
* 这是用于获取依赖项的快捷方法
*/
@Override
public Object resolveShortcut(BeanFactory beanFactory) {
return beanFactory.getBean(this.shortcut, this.requiredType);
}
}
2.4.4 AutowiredMethodElement.inject执行@Autowired、@Value、@Inject方法注解解析注入
InjectedElement的子类AutowiredMethodElement重写的inject方法用于执行方法上的@Autowired、@Value、@Inject注解的解析和注入。
对于方法上的@Autowired等注解注入的逻辑, byType优先于byName的原理同样是resolveDependency方法,这个方法此前我们就详细介绍过了。
另外,这里还有一个缓存的逻辑,只要经过了第一次解析,那么就会设置缓存,其中就有ShortcutDependencyDescriptor的应用,这就和doResolveDependency方法的开头调用resolveShortcut方法快速获取依赖的逻辑联系起来了!
需要注意的是即使存在缓存,也会去beanFactory中查找,可能会触发的bean实例的创建和初始化,因为依赖项可能是prototype的。
/**
* AutowiredAnnotationBeanPostProcessor的内部类
* <p>
* 表示自动注入注解(@Autowired、@Value、@Inject)方法的注入信息的类。
*/
private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
/**
* 是否是必须依赖
*/
private final boolean required;
/**
* 是否以缓存,即该注入点是否已被解析过
*/
private volatile boolean cached = false;
/**
* 缓存的已被解析的方法参数值数组,单个元素可能是DependencyDescriptor或者ShortcutDependencyDescriptor
* 或者cachedMethodArguments就是null
*/
@Nullable
private volatile Object[] cachedMethodArguments;
/**
* 构造器
*
* @param required 是否是必须依赖
*/
public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
super(method, pd);
this.required = required;
}
/**
* InjectedElement的子类内部类AutowiredFieldElement重写的方法
* <p>
* 完成方法注入点的注入操作,包括@Autowired、@Value、@Inject注解的解析
*
* @param bean 需要进行注入的目标实例
* @param beanName beanName
* @param pvs 已找到的属性值数组,用于防止重复注入
*/
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
/*
* 2 检查是否可以跳过该"属性"注入,也就是看此前找到的pvs中是否存在该名字的属性,如果存在就跳过,不存在就不跳过
* 这里可以发现:
* setter方法的注入流程的优先级为:XML手动设置的property > XML设置自动注入的找到的property -> 注解设置的property
* 前面的流程中没找到指定名称的property时,当前流程才会查找property
*/
if (checkPropertySkipping(pvs)) {
return;
}
//获取方法
Method method = (Method) this.member;
Object[] arguments;
//如果已被缓存过,只要调用过一次该方法,那么cached将被设置为true,后续都走resolveCachedArguments
if (this.cached) {
// 走缓存的逻辑,获取需要注入的依赖项数组
arguments = resolveCachedArguments(beanName);
} else {
//获取参数数量
int argumentCount = method.getParameterCount();
//需要注入的参数值数组
arguments = new Object[argumentCount];
//新建依赖描述符集合
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
//自动注入的beanName集合
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
//获取转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
/*遍历每一个属性,进行注入*/
for (int i = 0; i < arguments.length; i++) {
//新建方法参数对象
MethodParameter methodParam = new MethodParameter(method, i);
//新建当前参数的描述符对象,这里的required属性就是@Autowired注解的required属性值,没有就设置默认true
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
//加入到descriptors集合中
descriptors[i] = currDesc;
try {
/*
* 调用resolveDependency方法根据类型解析依赖,返回找到的依赖,查找规则在之前讲过,注意这里的required是可以设置的
* 如果required设置为false,那么没找到依赖将不会抛出异常
* 如果找到多个依赖,那么会尝试查找最合适的依赖,就掉调用determineAutowireCandidate方法,此前就讲过了
* 在最后一步会尝试根据name进行匹配,如果还是不能筛选出合适的依赖,那么抛出异常
* 这就是byType优先于byName的原理,实际上一个resolveDependency方法就完成了
*/
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
//如果返回null并且是非必须依赖
if (arg == null && !this.required) {
//参数值数组置为null
arguments = null;
//直接结束循环
break;
}
//否则,对应位置存入找到的依赖项
arguments[i] = arg;
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
/*同步,设置缓存,类似于AutowiredFieldElement中的步骤*/
synchronized (this) {
//如果没有被缓存,那么尝试将解析结果加入缓存
if (!this.cached) {
//如果arguments数组不为null
if (arguments != null) {
//拷贝描述符数组
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
///将每一个autowiredBeanName和beanName的依赖关系注册到dependentBeanMap和dependenciesForBeanMap缓存中
//表示beanName的实例依赖autowiredBeanName的实例,这个方法我们在前面就讲过了
registerDependentBeans(beanName, autowiredBeans);
//如果依赖bean等于参数个数,即一个参数只会注入一个依赖
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
//获取依赖beanName
String autowiredBeanName = it.next();
//如果工厂中包含该bean并且类型匹配
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
/*
* 将当前desc描述符、beanName、字段类型存入一个ShortcutDependencyDescriptor对象中,随后赋给cachedMethodArguments
* 的对应索引位置,后续查找时将直接获取就有该beanName和字段类型的依赖实例返回
*/
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
//将cachedMethodArguments赋值给cachedMethodArguments对象变量,方便后续查找
this.cachedMethodArguments = cachedMethodArguments;
} else {
//如果arguments为null并且不是必须依赖,那么清空缓存
//下一次走resolveCachedArguments方法时,直接返回null
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
//如果arguments不为null
if (arguments != null) {
try {
//设置方法的可访问属性,即method.setAccessible(true)
ReflectionUtils.makeAccessible(method);
/*
* 反射回调方法,采用获取的依赖项作为参数
*/
method.invoke(bean, arguments);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
/**
* 解析指定的已缓存的方法参数,快速可获取需要注入的依赖项数组
*
* @param beanName beanName
* @return 需要注入的依赖项数组
*/
@Nullable
private Object[] resolveCachedArguments(@Nullable String beanName) {
//获取缓存
Object[] cachedMethodArguments = this.cachedMethodArguments;
//如果为null,这是第一次解析依赖返回null并且是非必须依赖的情况,这种情况直接返回null
if (cachedMethodArguments == null) {
return null;
}
//存储找到的依赖项
Object[] arguments = new Object[cachedMethodArguments.length];
//遍历
for (int i = 0; i < arguments.length; i++) {
//调用resolvedCachedArgument方法,查找每一个cachedMethodArguments的描述符,将返回的依赖项存入对应的arguments的索引位置
arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
}
return arguments;
}
}
2.5 applyPropertyValues属性setter装配
应用从< property>标签和byName或者byType找到的属性值,在此前已经应用过某些注解注入了。这个方法也可以说是为基于XML的setter属性注入准备的,纯粹的注解注入在前一步postProcessProperties已经完成了。这里的“属性”注入,都是setter方法注入。
但是该方法主要是进行属性的类型转换,真正的属性注入还是依赖内部通过BeanWrapper调用的setPropertyValues方法,这就是BeanWrapper的功能——设置bean实例的属性!
/**
* AbstractAutowireCapableBeanFactory的方法
* <p>
* 应用从<property>标签和byName或者byType找到的属性值,在此前已经应用过某些注解注入了
* 这个方法可以说是为基于XML的setter属性注入准备的,纯粹的注解注入在前一步postProcessProperties已经完成了
*
* @param beanName beanName,主要用于异常信息输出
* @param mbd 合并的bean定义
* @param bw BeanWrapper,包装了目标对象
* @param pvs 属性值集合
*/
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//如果是属性值集合为空,直接返回
if (pvs.isEmpty()) {
return;
}
//安全管理器相关,不考虑
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
//如果属于MutablePropertyValues,一般都是这个类型
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//如果已转换类型,这个第一次创建bean的时候一般是false,后续可能为true
//第一次解析之后会存储起来,后续走这个判断,直接使用"捷径"
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
//已转换类型,通过bw调用setPropertyValues注入属性值,完事儿直接返回
bw.setPropertyValues(mpvs);
return;
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
//如果没转换,那么获取内部的原始PropertyValue属性值集合
original = mpvs.getPropertyValueList();
} else {
//如果不是MutablePropertyValues类型,那么原始属性值数组转换为集合
original = Arrays.asList(pvs.getPropertyValues());
}
/*
* 获取AbstractBeanFactory中的typeConverter自定义类型转换器属性,该属性用来覆盖默认属性编辑器PropertyEditor
* 并没有提供getCustomTypeConverter方法的默认返回,因此customConverter默认返回null,我们同样可以自己扩展
* 如果自定义类型转换器customConverter不为null,那么就使用customConverter
* 否则使用bw对象本身,因为BeanWrapper也能实现类型转换,一般都是使用bw本身
*/
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//初始化一个valueResolver对象,用于将 bean 定义对象中包含的值解析为应用于目标 bean 实例的实际值
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 创建深克隆副本,存放解析后的属性值
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
//resolveNecessary表示是否需要解析,默认为false
boolean resolveNecessary = false;
//遍历原始值属性集合的每一个属性,转换类型
for (PropertyValue pv : original) {
/*
* 如果单个属性已解析,直接加入解析值集合中
*/
if (pv.isConverted()) {
deepCopy.add(pv);
}
/*
* 如果没有转换过,那么需要转换
*/
else {
//获取属性名
String propertyName = pv.getName();
//获取属性值
Object originalValue = pv.getValue();
//一般都不是AutowiredPropertyMarker实例
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
/*
* 第一次转换
* 这里的resolveValueIfNecessary方法,则是将之前的值包装类转换为对应的实例Java类型,比如ManagedArray转换为数组、ManagedList转换为list集合
* 如果是引用其他bean或者指定了另一个bean定义,比如RuntimeBeanReference,则在这里会先初始化该引用的bean实例并返回
* 相当于反解回来,这里的resolvedValue就是转换后的实际Java类型,这就是所谓的转换,这也是前面所说的运行时解析,就是这个逻辑
*
* 之前就讲过了,在resolveConstructorArguments方法解析构造器参数的时候也用的是这个方法转换类型
*/
//第一次转换的值
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//第二次转换的值
Object convertedValue = resolvedValue;
//是否可以转换
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
//第二次转换
//这里才是尝试将已解析的属性值继续转换为setter方法参数类型的逻辑,在上面的resolveValueIfNecessary中仅仅是将值得包装对象解析为Java值类型而已
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
/*
* 在合并的BeanDefinition中存储转换后的值,以避免为每个创建的bean实例重新转换
*/
//如果原值等于转换后的值,原值一般都是RuntimeBeanReference、ManagedArray、TypedStringValue等包包装类一般都不相等,
if (resolvedValue == originalValue) {
//设置当前PropertyValue的converted属性为true,convertedValue属性为当前已转换的convertedValue值
if (convertible) {
pv.setConvertedValue(convertedValue);
}
//加入解析值集合中
deepCopy.add(pv);
}
//如果属性支持转换,并且原始值属于String,并且原始值是非动态的,并且转换后的值不是Collection或者数组
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
//设置当前PropertyValue的converted属性为true,convertedValue属性为当前已转换的convertedValue值
pv.setConvertedValue(convertedValue);
//加入解析值集合中
deepCopy.add(pv);
}
//否则
else {
//resolveNecessary设置为true,表示还需要继续解析
resolveNecessary = true;
//根据新值创建一个PropertyValue加入解析值集合中
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
//如果是MutablePropertyValues类型,并且不需要继续解析了
if (mpvs != null && !resolveNecessary) {
//那么当前MutablePropertyValues的converted标记为true
mpvs.setConverted();
}
/*
* 根据转换之后的属性值deepCopy新建一个MutablePropertyValues,通过bw调用setPropertyValues注入属性值
* 这个方法的调用链比较长,后续解析
*/
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
2.5.1 setPropertyValues注入属性值
该方法位于BeanWrapper的父类AbstractPropertyAccessor中,主要功能是通过反射调用setter方法,将解析的属性值注入进去,也就是注入到参数中去。
但是该方法的主要做的仅仅是遍历属性值列表以及处理抛出的异常,每一个属性的真正注入还需要继续深入到内部的setPropertyValue方法中,该方法被子类AbstractNestablePropertyAccessor的重写了。
/**
* AbstractPropertyAccessor的方法
* <p>
* 反射调用setter方法,将解析的属性值注入进去
*
* @param pvs 解析之后的属性值
*/
@Override
public void setPropertyValues(PropertyValues pvs) throws BeansException {
//调用另一个setPropertyValues方法,不忽略异常
setPropertyValues(pvs, false, false);
}
/**
* AbstractPropertyAccessor的方法
* <p>
* 反射调用setter方法,注入已解析的属性值
*
* @param pvs 解析之后的属性值
* @param ignoreUnknown 是否忽略NotWritablePropertyException异常
* @param ignoreInvalid 是否忽略NullValueInNestedPathException异常
*/
@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException {
//抛出属性注入时抛出的PropertyAccessException异常
List<PropertyAccessException> propertyAccessExceptions = null;
//获取以解析的属性值集合
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
//遍历集合,进行注入
for (PropertyValue pv : propertyValues) {
try {
/*
* 属性注入的核心方法,这个方法由子类AbstractNestablePropertyAccessor重写了
*
* 如果该方法存在严重的异常(如没有匹配字段),此方法可能会抛出任何BeanException
* 此处不会捕获这些异常,Spring只能尝试处理不太严重的异常
*/
setPropertyValue(pv);
} catch (NotWritablePropertyException ex) {
//如果不忽略,那么抛出异常
if (!ignoreUnknown) {
throw ex;
}
//否则,只需忽略它并继续...
} catch (NullValueInNestedPathException ex) {
//如果不忽略,那么抛出异常
if (!ignoreInvalid) {
throw ex;
}
//否则,只需忽略它并继续...
} catch (PropertyAccessException ex) {
//收集PropertyAccessException异常
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
}
//注入完毕之后,如果propertyAccessExceptions异常集合不为null,说明抛出过PropertyAccessException异常,在这里统一抛出
if (propertyAccessExceptions != null) {
//抛出异常集合的第一个异常元素
PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
throw new PropertyBatchUpdateException(paeArray);
}
}
2.5.1.1 setPropertyValue注入属性值
反射调用setter方法,注入已解析的属性值。支持嵌套属性的赋值,比如为某个集合属性的某个索引赋值或者某个对象属性的属性赋值,可以解析特殊符号,比如"."、"[ ]"等,也就是复合引用,我们在IoC学习的时候的"name复合属性名称注入"部分已经介绍如何使用了。
/**
1. AbstractNestablePropertyAccessor的方法
2. <p>
3. 反射调用setter方法,注入已解析的属性值
4. 5. @param pv 属性值包装对象
*/
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
/*
* 获取当前属性内部的PropertyTokenHolder,第一次注入时默认为null
* PropertyTokenHolder主要用于保存属性的名称、路径,以及集合的索引等信息
*
* 如果某复合属性路径的最终目的是为集合或者数组的某个索引"直接赋值"或者为map的key的value赋值,即结尾是[ ]的形式
* 那么内部的keys数组属性保存最后追踪的索引,其他情况下内部的keys属性为null
*/
PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
//如果tokens为null,那么需要获取
if (tokens == null) {
//获取属性名
String propertyName = pv.getName();
AbstractNestablePropertyAccessor nestedPa;
try {
/*
* 获取属性访问器。顾名思义,Spring通过属性访问器访问、操作属性的,类型为AbstractNestablePropertyAccessor
* 它的特点是支持嵌套属性的赋值,比如为某个集合属性的某个索引赋值或者某个对象属性的属性赋值,可以解析特殊符号,比如"."、"[ ]"等
* 这一点,我们在IoC学习的时候的"name复合属性名称注入"部分已经介绍如何使用了
*
* 如果不存在属性分隔符".",默认就是返回当前的BeanWrapperImpl实例(不解析key中的路径分隔符,比如"map[my.key]",算作没有)
*/
nestedPa = getPropertyAccessorForPropertyPath(propertyName);
} catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Nested property in path '" + propertyName + "' does not exist", ex);
}
//获取PropertyTokenHolder
tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
//如果路径中没有属性分隔符".",那么保存resolvedTokens属性
if (nestedPa == this) {
pv.getOriginalPropertyValue().resolvedTokens = tokens;
}
//委托属性访问器设置属性
nestedPa.setPropertyValue(tokens, pv);
} else {
//如果tokens不为null,那么直接使用当前的bw设置属性
setPropertyValue(tokens, pv);
}
}
内部还使用了另一个setPropertyValue方法,从两个路径设置属性值:
- 如果某复合属性路径的最终目的是为集合或者数组的某个索引"直接赋值"或者为map的key的value赋值,即结尾是[ ]的形式。那么keys不为null,这种情况下的属性注入,调用processKeyedProperty方法,很少用到。
- 其他情况下的属性注入,调用processLocalProperty,一般都是这个逻辑。
/**
* AbstractNestablePropertyAccessor的方法
* <p>
* 通过属性访问器设置属性
*
* @param tokens 当前属性的PropertyTokenHolder
* @param pv 当前属性包装类
*/
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
//如果某复合属性路径的最终目的是为集合或者数组的某个索引"直接赋值"或者为map的key的value赋值,即结尾是[ ]的形式
//那么keys不为null,这种情况下的属性注入,调用processKeyedProperty方法,很少用到
if (tokens.keys != null) {
processKeyedProperty(tokens, pv);
}
//其他情况下的属性注入,调用processLocalProperty,一般都是这个逻辑
else {
processLocalProperty(tokens, pv);
}
}
2.5.1.1.1 processLocalProperty一般属性注入
一般情况下的属性setter方法注入。
/**
1. AbstractNestablePropertyAccessor的方法
2. <p>
3. 一般情况下的属性setter注入
*/
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
//获取属性处理器,用于反射获取、调用属性的getter和setter方法
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
//不存在或者不可写
if (ph == null || !ph.isWritable()) {
//如果属性是Optional类型,则直接返回,其他情况下则抛出异常
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + tokens.actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
} else {
throw createNotWritablePropertyException(tokens.canonicalName);
}
}
Object oldValue = null;
try {
//获取原始属性值,对于在上面的applyPropertyValues方法中
//对于String的值还是TypedStringValue,并且isConverted为true,对于其他复杂类型,则是解析后的值,并且isConverted为false
Object originalValue = pv.getValue();
//转换后的值
Object valueToApply = originalValue;
//如果有转换的必要,第一次进来时conversionNecessary属性为null,所有都必要
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
//如果已转换
if (pv.isConverted()) {
//注解获取转换后的值
valueToApply = pv.getConvertedValue();
}
//如果需要转换,那么转换
else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
} catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + tokens.canonicalName + "'", ex);
}
}
}
//转换类型,内部调用了convertIfNecessary方法
valueToApply = convertForProperty(
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
}
//最后判断转换后的值是否不等于转换前的值,并将结果设置为conversionNecessary属性的值
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
//最后通过ph反射调用setter方法设置值
ph.setValue(valueToApply);
} catch (TypeMismatchException ex) {
throw ex;
} catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
} else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
} catch (Exception ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
3 initializeBean初始化bean实例
在经过createBeanInstance方法"实例化"bean以及populateBean方法对bean实例进行"填充"之后。继续调用initializeBean方法,对bean实例进行进一步初始化,主要回调各种方法,顺序为:
- 回调一些特殊的Aware接口的方法,包括BeanNameAware、BeanClassLoaderAware、BeanFactoryAware;
- 回调所有BeanPostProcessor的postProcessBeforeInitialization方法,包括@PostConstruct注解标注的初始化方法;
- 回调所有配置的initMethod方法,包括InitializingBean.afterPropertiesSet()和init-method;
- 回调所有BeanPostProcessor的postProcessAfterInitialization方法。
/**
* AbstractAutowireCapableBeanFactory的方法
* <p>
* 初始化给定的 bean 实例,主要是应用各种回调方法:
* 1 回调一些特殊的Aware接口的方法,包括BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
* 2 回调所有BeanPostProcessor的postProcessBeforeInitialization方法,包括@PostConstruct注解标注的初始化方法
* 3 回调所有配置的init-method方法,包括InitializingBean.afterPropertiesSet()和init-method
* 4 回调所有BeanPostProcessor的postProcessAfterInitialization方法
*
* @param beanName 工厂中的bean名称(用于调试目的)
* @param bean 可能需要初始化的新 bean 实例
* @param mbd 创建 bean 的 bean 定义(如果给定现有 bean 实例,也可以为 null)
* @return 初始化 bean 实例(可能已包装)
*/
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
/*
* 1 一些特殊的Aware接口的回调,BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
*/
//如果存在安全管理器,一般不存在
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
} else {
//回调
invokeAwareMethods(beanName, bean);
}
/*
* 2 initMethod调用之前回调所有BeanPostProcessor的postProcessBeforeInitialization方法
*
* 其中就包括@PostConstruct注解标注的初始化方法的调用,在applyMergedBeanDefinitionPostProcessors方法中已经解析了该注解
*/
Object wrappedBean = bean;
//如果mbd为null或者不是合成的,一般都不是
if (mbd == null || !mbd.isSynthetic()) {
//回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
/*
* 3 回调所有配置的initMethod初始化方法
* 包括InitializingBean.afterPropertiesSet(),以及XML配置的init-method属性指定的方法
*/
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
/*
* 4 initMethod调用之后回调所有BeanPostProcessor的postProcessAfterInitialization方法
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
//返回最终的结果
return wrappedBean;
}
3.1 invokeAwareMethods回调Aware的方法
一些特殊的Aware接口的回调,顺序为(如果存在):
1 BeanNameAware.setBeanName(name)
2 BeanClassLoaderAware.setBeanClassLoader(classLoader)
3 BeanFactoryAware.setBeanFactory(beanFactory)
这些Aware接口在此前的createBeanFactory方法中已经被加入到了忽略setter方法的自动装配的集合ignoredDependencyInterfaces中。
Aware接口是一类非常重要的扩展接口,用于从容器中获取各种属性和对象。
/**
1. AbstractAutowireCapableBeanFactory的方法
2. <p>
3. 一些特殊的Aware接口的回调,顺序为(如果存在):
4. 1 BeanNameAware.setBeanName(name)
5. 2 BeanClassLoaderAware.setBeanClassLoader(classLoader)
6. 3 BeanFactoryAware.setBeanFactory(beanFactory)
7. <p>
8. 这些Aware接口在此前的createBeanFactory方法中已经被加入到了忽略setter方法的自动装配的集合ignoredDependencyInterfaces中
9. 10. @param beanName beanName
11. @param bean bean实例
*/
private void invokeAwareMethods(String beanName, Object bean) {
/*如果属于Aware接口*/
if (bean instanceof Aware) {
/*
* 1 如果属于BeanNameAware,那么回调setBeanName方法,将beanName作为参数
*/
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
/*
* 2 如果属于BeanClassLoaderAware,那么回调setBeanClassLoader方法,将ClassLoader作为参数
*/
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
/*
* 3 如果属于BeanFactoryAware,那么回调setBeanFactory方法,将当前beanFactory作为参数
*/
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
3.2 applyBeanPostProcessorsBeforeInitialization回调BeanPostProcessor.postProcessBeforeInitialization方法
initMethod调用之前回调所有BeanPostProcessor的postProcessBeforeInitialization方法。
- 最开始学的ApplicationContextAwareProcessor的postProcessBeforeInitialization用于向实现了Aware接口的子接口EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAwarebean的bean中注入相应的属性,即调用相关的setter方法,传入参数;
- InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization用于回调此前通过applyMergedBeanDefinitionPostProcessors找到的具有@PostConstruct注解标注的初始化方法;
- 而CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor等后处理器的postProcessBeforeInitialization方法则默认返回参数bean,没有其他任何逻辑。
/**
1. AbstractAutowireCapableBeanFactory的方法
2. <p>
3. init-method调用之前回调所有BeanPostProcessor的postProcessBeforeInitialization方法
4. 也就是@PostConstruct注解标注的初始化方法,在applyMergedBeanDefinitionPostProcessors方法中已经解析了该注解
5. 6. @param existingBean bean实例
7. @param beanName beanName
8. @return 应用之后的返回值
*/
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
//最终返回的结果
Object result = existingBean;
//遍历所有已注册的BeanPostProcessor,按照遍历顺序回调postProcessBeforeInitialization方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
//如果途中某个processor的postProcessBeforeInitialization方法返回null,那么不进行后续的回调
//直接返回倒数第二个processor的postProcessBeforeInitialization方法的返回值
if (current == null) {
return result;
}
//改变result指向当前的返回值
result = current;
}
//返回result
return result;
}
3.3 invokeInitMethods回调初始化方法
applyBeanPostProcessorsBeforeInitialization方法之后继续回调invokeInitMethods初始化方法,该方法内部的回调顺序为:
- InitializingBean.afterPropertiesSet()方法。
- XML配置的init-method方法。
从源码中能看出来,初始化方法的之行顺序为:@PostConstruct标注的初始化方法、InitializingBean.afterPropertiesSet()方法、XML配置的init-method方法。并且,如果他们都配置了同一个方法名,那么该方法只会执行一次。实际上这个特点我们在IoC学习的部分已经讲过了。
/**
* AbstractAutowireCapableBeanFactory的方法
* <p>
* 回调自定义的initMethod初始化方法,顺序为:
* 1 InitializingBean.afterPropertiesSet()方法
* 2 XML配置的init-method方法
*
* @param beanName 工厂中的bean名称(用于调试目的)
* @param bean 可能需要初始化的新 bean 实例
* @param mbd 创建 bean 的 bean 定义(如果给定现有 bean 实例,也可以为 null)
*/
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//bean实例是否属于InitializingBean
boolean isInitializingBean = (bean instanceof InitializingBean);
/*
* 1 如果属于InitializingBean
* 2 并且externallyManagedInitMethods集合中不存在afterPropertiesSet方法
* 前面的在LifecycleMetadata的checkedInitMethods方法中我们就知道,通过@PostConstruct标注的方法会被存入externallyManagedInitMethods中
* 如果此前@PostConstruct注解标注了afterPropertiesSet方法,那么这个方法不会被再次调用,这就是externallyManagedInitMethods防止重复调用的逻辑
*/
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
//回调afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
//获取initMethodName属性,就是XML的init-method属性
String initMethodName = mbd.getInitMethodName();
/*
* 1 如果存在init-method方法
* 2 并且不是InitializingBean类型或者是InitializingBean类型但是initMethodName不是"afterPropertiesSet"方法
* 这里也是防止重复调用同一个方法的逻辑,因为在上面会调用afterPropertiesSet方法,这里不必再次调用
* 3 并且externallyManagedInitMethods集合中不存在该方法
* 在LifecycleMetadata的checkedInitMethods方法中我们就知道,通过@PostConstruct标注的方法会被存入externallyManagedInitMethods中
* 如果此前@PostConstruct注解标注了afterPropertiesSet方法,那么这个方法不会被再次调用,这就是externallyManagedInitMethods防止重复调用的逻辑
*/
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//反射回调init-method的方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
3.4 applyBeanPostProcessorsAfterInitialization回调BeanPostProcessor.postProcessAfterInitialization方法
initMethod调用之后应用所有已注册的BeanPostProcessor后处理器的postProcessAfterInitialization方法。
Spring核心依赖中提供的后处理器在这个扩展点并没有做额外的事,但是我们可以自己扩展。但是如果我们引入了spring-aop的依赖,那么该方法就非常重要了,比如aop包中的AbstractAutoProxyCreator和AbstractAdvisingBeanPostProcessor这两个后处理器都重写了该方法,都被用于根据原始对象来创建代理对象,进而执行AOP增强,比如自定义AOP逻辑、Spring事务、Spring异步任务等操作。Spring AOP的源码在后面我们会见到。
/**
* AbstractAutowireCapableBeanFactory的方法
*
* initMethod调用之后应用所有已注册的BeanPostProcessor后处理器的postProcessAfterInitialization方法
*
* @param existingBean 现有的 bean 实例
* @param beanName beanName
* @return 要使用的 bean 实例,无论是原始实例还是包装实例
*/
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
//用来保存返回的结果,默认为传递的existingBean
Object result = existingBean;
//遍历全部已注册的BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//按照遍历顺序调用postProcessAfterInitialization方法
Object current = processor.postProcessAfterInitialization(result, beanName);
//如果当前BeanPostProcessor后处理器的返回值为null,那么返回上一个不为null的结果
if (current == null) {
return result;
}
//更新要返回的结果
result = current;
}
//遍历、处理完毕,返回最终的结果
return result;
}
4 registerDisposableBeanIfNecessary注册销毁回调
将符合条件的给定的 bean 添加到此工厂中的disposableBeans缓存中,仅适用于单例,在容器被销毁时会进行销毁回调。
/**
* AbstractBeanFactory的方法
* <p>
* 将符合条件的给定的 bean 添加到此工厂中的disposableBeans缓存中,仅适用于单例,在被容器销毁时会进行销毁回调
*
* @param beanName beanName
* @param bean bean 实例
* @param mbd bean的bean定义
*/
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
//mbd的scope不是"prototype"类型,并且给定bean需要销毁
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
//如果是单例的
if (mbd.isSingleton()) {
//根据当前bean新建一个DisposableBeanAdapter与beanName一起存入disposableBeans缓存中,后续将会被调用
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
} else {
//其他scope的处理
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
4.1 requiresDestruction判断是否需要销毁
requiresDestruction用于判断是否需要进行销毁回调!
如果bean不是null,并且(具有合理的destroy销毁回调方法,或者(注册了任何DestructionAwareBeanPostProcessors后处理器,并且给定的bean可以被至少一个具有销毁感知的后处理器DestructionAwareBeanPostProcessor处理))。满足以上条件,则表示该bean实例需要被销毁,也就是需要进行销毁回调。
/**
1. 确定给定的 bean 是否需要在shutdown时销毁。
2. 默认实现检查DisposableBean接口、指定的销毁方法、注册的DestructionAwareBeanPostProcessor后处理器
3. 4. @param bean 要检查的 bean 实例
5. @param mbd 相应的bean定义
*/
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
//如果bean不是null,并且(具有合理的destroy销毁回调方法,或者(注册了任何DestructionAwareBeanPostProcessors后处理器,并且给定的 bean
//可以被至少一个具有销毁感知的后处理器DestructionAwareBeanPostProcessor处理))
//满足以上条件,则表示该bean实例需要被销毁
return (bean.getClass() != NullBean.class &&
(DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}
4.1.1 hasDestroyMethod是否具有销毁回调方法
检查给定的 bean 是否有销毁方法要调用,返回true表示需要,false表示不需要。
- 如果bean属于DisposableBean类型或者属于AutoCloseable类型,那么返回true;
- 获取destroyMethodName属性,就是XML的destroy-method属性:
- 如果属性值为"(inferred)",表示需要Spring进行销毁方法的自动推断。目前Spring推断规则是:如果该类中存在名为"close" 或者 "shutdown"的方法,就返回true,否则返回false。
- 否则,判断属性值是否不为null以及"",即是否设置了其他方法作为destroy-method属性,如果是那么返回true,否则返回false。
/**
* DisposableBeanAdapter的属性常量
* 表示close方法名
*/
private static final String CLOSE_METHOD_NAME = "close";
/**
* DisposableBeanAdapter的属性常量
* 表示shutdown方法名
*/
private static final String SHUTDOWN_METHOD_NAME = "shutdown";
/**
* AbstractBeanDefinition的属性常量
* 表示需要Spring进行方法推断
*/
public static final String INFER_METHOD = "(inferred)";
/**
* DisposableBeanAdapter的方法
* <p>
* 检查给定的 bean 是否有销毁方法要调用
*
* @param bean bean实例
* @param beanDefinition 相应的bean定义
*/
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
//如果bean属于DisposableBean类型或者属于AutoCloseable类型,那么返回true
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
return true;
}
//获取destroyMethodName属性,就是XML的destroy-method属性
String destroyMethodName = beanDefinition.getDestroyMethodName();
//如果destroyMethodName属性值为"(inferred)",表示需要Spring进行销毁方法的自动推断
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
//目前Spring推断规则是:如果该类中存在名为"close" 或者 "shutdown"的方法,就返回true否则返回false
return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
}
//否则,判断destroyMethodName属性是否不为null以及"",即是否设置了destroy-method属性,如果是那么返回true,否则返回false
return StringUtils.hasLength(destroyMethodName);
}
4.1.2 hasApplicableProcessors是否需要被后处理器销毁
如果已注册的bean后处理器中存在DestructionAwareBeanPostProcessor类型的后处理器,并且存在至少一个该类型的后处理器可以对该bean进行销毁回调,那么返回true,否则返回false。
通过requiresDestruction扩展点方法判断,常见的实现就是InitDestroyAnnotationBeanPostProcessor,它会判断该实例所属的类中是否存在@PreDestroy注解的标注方法。
/**
* DisposableBeanAdapter的方法
* <p>
* 检查给定的 bean 是否应用了某个具有销毁感知的后处理器
* 实际上默认就是查找该实例所属的类是否具有标注了@PreDestroy注解的方法
*
* @param bean bean 实例
* @param postProcessors 注册的bean后处理器集合
*/
public static boolean hasApplicableProcessors(Object bean, List<BeanPostProcessor> postProcessors) {
if (!CollectionUtils.isEmpty(postProcessors)) {
//遍历集合
for (BeanPostProcessor processor : postProcessors) {
//如果属于DestructionAwareBeanPostProcessor类型
if (processor instanceof DestructionAwareBeanPostProcessor) {
//强转
DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
//调用requiresDestruction方法,用于判断确定给定的 bean 实例是否需要此后处理器进行销毁回调
//常见的实现就是InitDestroyAnnotationBeanPostProcessor,它会判断该实例所属的类中是否存在@PreDestroy注解的方法
//如果存在就返回true,不存在就返回false,当bean销毁的时候就会调用postProcessBeforeDestruction方法回调注解方法
if (dabpp.requiresDestruction(bean)) {
return true;
}
}
}
}
return false;
}
4.1.2.1 InitDestroyAnnotationBeanPostProcessor.requiresDestruction回调检查@PreDestroy注解
DestructionAwareBeanPostProcessor后处理器的常见实现就是InitDestroyAnnotationBeanPostProcessor,它的requiresDestruction方法会判断该实例所属的类中是否存在@PreDestroy注解的标注方法,如果存在,返回true,否则返回false。
在进行销毁回调的时候,会通过调用postProcessBeforeDestruction方法回调被@PreDestroy注解的标注方法。
/**
* InitDestroyAnnotationBeanPostProcessor的方法
* <p>
* 判断给定实例所属的类中是否存在@PreDestroy注解的方法
*
* @param bean bean实例
* @return 如果存在,返回true,否则返回false
*/
@Override
public boolean requiresDestruction(Object bean) {
//调用findLifecycleMetadata查找回调元数据,随后调用hasDestroyMethods判断是否具有销毁回调方法
return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();
}
/**
* InitDestroyAnnotationBeanPostProcessor的内部类LifecycleMetadata的方法
*
* @return 是否具有@PreDestroy注解标注的销毁回调方法
*/
public boolean hasDestroyMethods() {
//判断这两个缓存中是否具有存在@PreDestroy注解的销毁回调方法
Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods;
Collection<LifecycleElement> destroyMethodsToUse =
(checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
return !destroyMethodsToUse.isEmpty();
}
4.2 DisposableBeanAdapter可销毁bean适配器
DisposableBeanAdapter是可销毁bean适配器。在最开始“容器初始化(2)”的文章中销毁容器的那部分我们就见过了这个类,实际上最终的销毁回调也是通过这个类的destroy()方法完成的。
构造DisposableBeanAdapter的时候,会初始化很多属性,我们来看一下源码。从源码中能够知道,销毁回调同样会避免同一个方法的的重复调用!
//-------DisposableBeanAdapter的相关属性----------
/**
* 保存bean实例
*/
private final Object bean;
/**
* 保存beanName
*/
private final String beanName;
/**
* 是否需要回调DisposableBean的destroy方法
*/
private final boolean invokeDisposableBean;
/**
* 是否允许访问非公共构造函数和方法
*/
private final boolean nonPublicAccessAllowed;
/**
* 销毁方法名,来自于自动推断或者设置的destroy-method属性
*/
@Nullable
private String destroyMethodName;
/**
* 根据方法名获取的销毁方法
*/
@Nullable
private transient Method destroyMethod;
/**
* 处理器列表中的所有DestructionAwareBeanPostProcessors类型的并且支持处理当前bean实例的处理器列表
*/
@Nullable
private List<DestructionAwareBeanPostProcessor> beanPostProcessors;
/**
1. DisposableBeanAdapter的构造器
2. <p>
3. 使用给定的bean实例创建新的DisposableBeanAdapter
4. 5. @param bean bean 实例(从不为null )
6. @param beanName beanName
7. @param beanDefinition 已合并的bean定义
8. @param postProcessors 已注册的BeanPostProcessor集合,可能包含DestructionAwareBeanPostProcessor
*/
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {
Assert.notNull(bean, "Disposable bean must not be null");
this.bean = bean;
this.beanName = beanName;
/*
* 如果bean实例属于DisposableBean类型,并且@PreDestroy注解的标注的方法中没有名为"destroy"的方法
* 那么表示需要回调DisposableBean的destroy方法,invokeDisposableBean设置为true,否则设置为false
* 这里检查externallyManagedDestroyMethods集合的目的同样是防止同一个销毁方法的重复调用
*/
this.invokeDisposableBean =
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
//返回是否允许访问非公共构造函数和方法
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
this.acc = acc;
//推断destroyMethod方法名
String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
//如果找到了destroyMethod方法
//并且(不需要回调DisposableBean的destroy方法,或者destroyMethodName不等于"destroy"),防止同一个销毁方法的重复调用
//并且@PreDestroy注解的标注的方法中没有名为"destroy"的方法,用于防止同一个销毁方法的重复调用
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
//设置destroyMethodName属性
this.destroyMethodName = destroyMethodName;
//获取destroyMethod方法对象
Method destroyMethod = determineDestroyMethod(destroyMethodName);
//没找到该方法,并且没有默认的销毁方法,即没有default-destroy-method属性,那么抛出异常
if (destroyMethod == null) {
if (beanDefinition.isEnforceDestroyMethod()) {
throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
destroyMethodName + "' on bean with name '" + beanName + "'");
}
} else {
//获取方法参数
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
//如果参数个数大于1,那么抛出异常
if (paramTypes.length > 1) {
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
beanName + "' has more than one parameter - not supported as destroy method");
}
//如果参数个数为1,并且不是boolean类型,那么同样抛出异常
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
beanName + "' has a non-boolean parameter - not supported as destroy method");
}
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
}
//设置方法
this.destroyMethod = destroyMethod;
}
/*
* 过滤PostProcessor
* 搜索后处理器列表中的所有DestructionAwareBeanPostProcessors类型的并且支持处理当前bean实例的处理器列表
*/
this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
4.2.1 inferDestroyMethodIfNecessary推断销毁方法
该方法用于推断destroyMethod方法名,到这一步,一定是满足上面的hasDestroyMethod方法或者hasApplicableProcessors方法的要求。
- 获取destroyMethodName属性值,就是XML的destroy-method属性。
- 如果destroyMethodName值为"(inferred)",或者destroyMethodName为null并且bean实例属于AutoCloseable类型。
- 如果bean实例不属于DisposableBean类型,那么按照顺序先后尝试获取"close"以及"shutdown"方法名并返回,前提是这两个方法至少存在一个,无法推断则返回null;
- 否则,判断destroyMethodName属性是否不为null以及"",即是否设置了destroy-method属性,如果是那么直接返回设置的方法名,否则返回null。
/**
* DisposableBeanAdapter的属性常量
* 表示close方法名
*/
private static final String CLOSE_METHOD_NAME = "close";
/**
* DisposableBeanAdapter的属性常量
* 表示shutdown方法名
*/
private static final String SHUTDOWN_METHOD_NAME = "shutdown";
/**
* AbstractBeanDefinition的属性常量
* 表示需要Spring进行方法推断
*/
public static final String INFER_METHOD = "(inferred)";
/**
* DisposableBeanAdapter的方法
* <p>
* 推断destroyMethod方法名
* 1 如果没设置destroy-method属性(值为null或者"")那么返回null
* 2 如果设置了destroy-method属性:
* 2.1 如果值为"(inferred)",那么按照顺序先后尝试获取"close"以及"shutdown"方法名返回,前提是这两个方法至少存在一个,无法推断则返回null
* 2.2 如果是其他之值,那么直接返回设置的值
*
* @param bean bean实例
* @param beanDefinition bean定义
* @return destroyMethodName
*/
@Nullable
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
//获取destroyMethodName属性,就是XML的destroy-method属性
String destroyMethodName = beanDefinition.getDestroyMethodName();
//如果destroyMethodName值为"(inferred)",表示需要Spring进行销毁方法的自动推断
//或者destroyMethodName值为null,并且bean属于AutoCloseable,表示存在close方法(来自AutoCloseable接口)
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
//如果bean不属于DisposableBean类型,那么推断销毁方法以及进行Closeable的检测
if (!(bean instanceof DisposableBean)) {
try {
//首先尝试值获取close方法的方法名(简单名字),作为销毁回调方法的名字
//如果不存在该方法,会抛出异常
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
} catch (NoSuchMethodException ex) {
try {
//如果抛出了异常
//继续尝试值获取shutdown方法的方法名(简单名字),作为销毁回调方法的名字
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
} catch (NoSuchMethodException ex2) {
// no candidate destroy method found
//如果还是抛出异常,那么表示没有推断出候选销毁方法,但是该异常不会抛出
}
}
}
//直接返回null
return null;
}
//判断destroyMethodName属性是否不为null以及"",即是否设置了destroy-method属性,如果是那么返回设置的方法名,否则返回null
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}
4.2.2 filterPostProcessors过滤DestructionAwareBeanPostProcessor
搜索后处理器列表中的所有DestructionAwareBeanPostProcessors类型的并且支持处理当前bean实例的处理器列表并返回,方便后续调用。
/**
* 搜索后处理器列表中的所有DestructionAwareBeanPostProcessors类型的并且支持处理当前bean实例的处理器列表并返回
*
* @param processors 要搜索的列表
* @return 过滤的DestructionAwareBeanPostProcessors列表
*/
@Nullable
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
if (!CollectionUtils.isEmpty(processors)) {
filteredPostProcessors = new ArrayList<>(processors.size());
for (BeanPostProcessor processor : processors) {
//如果是DestructionAwareBeanPostProcessor类型,并且当前后处理器支持处理该bean实例,那么加入filteredPostProcessors集合中
if (processor instanceof DestructionAwareBeanPostProcessor) {
DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
if (dabpp.requiresDestruction(bean)) {
filteredPostProcessors.add(dabpp);
}
}
}
}
//返回
return filteredPostProcessors;
}
4.3 registerDisposableBean注册disposableBeans
将给定的 bean 添加到此注册表中的disposableBeans缓存中。disposableBeans缓存我们在“容器初始化(2)”的文章开头的destroySingletons方法中就见过了,到这里又见面了,我们终于知道它里面的元素是怎么来的了!
之前的文章在将destroy方法部分我就说过,当我们学到这里的时候,ClassPathXmlApplicationContext IoC容器的大概初始化过程就要结束了,这个过程从“销毁destroy”开始,到“创建create”结束,期间我们确实经历了容器由死而生的“九九八十一难”!
/**
* DefaultSingletonBeanRegistry的属性
* bean name到Disposable bean实例例映射的map,用于bean销毁的回调
*/
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
/**
* DefaultSingletonBeanRegistry的方法
* <p>
* 将给定的 bean 添加到此注册表中的disposableBeans缓存中。
* disposableBeans缓存我们在文章开头就看过了,到这里又见面了
*
* @param beanName beanName
* @param bean bean 实例
*/
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
//存入disposableBeans缓存
this.disposableBeans.put(beanName, bean);
}
}
5 finishRefresh完成刷新
上面的方法结束之后,refresh方法中的finishBeanFactoryInitialization方法就算结束了。
剩下的就是refresh方法中的最后一步finishRefresh方法,这一步主要是发布一些事件,以及调用生命周期处理器LifecycleProcessor的onRefresh()方法自动启动所有SmartLifecycle类型的bean,即回调它们的start()方法,这个地方就是一个容器生命周期的回调。
当finishRefresh方法完毕之后,refresh方法就算结束了,我们终于走完了IoC容器初始化的大概全部流程!
/**
* 完成此上下文的刷新,调用生命周期处理器LifecycleProcessor的onRefresh()方法并发布事件
*/
protected void finishRefresh() {
//清除resourceCaches资源缓存
clearResourceCaches();
//为此上下文初始化生命周期处理器LifecycleProcessor
initLifecycleProcessor();
//将刷新事件传播到生命周期处理器,启动所有SmartLifecycle类型的bean
getLifecycleProcessor().onRefresh();
//发布ContextRefreshedEvent事件
publishEvent(new ContextRefreshedEvent(this));
//创建一个MBeanServer(如果环境变量中spring.liveBeansView.mbeanDomain属性存在)
LiveBeansView.registerApplicationContext(this);
}
5.1 clearResourceCaches清除资源缓存
清除此次加载程序中的所有资源缓存。
/**
* DefaultResourceLoader的属性,资源缓存
*/
private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap<>(4);
/**
* DefaultResourceLoader的方法
* <p>
* 清除此资源加载程序中的所有资源缓存
*/
public void clearResourceCaches() {
this.resourceCaches.clear();
}
5.2 initLifecycleProcessor初始化生命周期处理器LifecycleProcessor
为此上下文初始化生命周期处理器LifecycleProcessor,如果上下文中未定义任何名为"lifecycleProcessor"的bean,则使用默认生命循环处理器DefaultLifecycleProcessor。
/**
* 工厂中的自定义的生命周期处理器 bean 的名称。 如果未提供,则使用默认生命循环处理器DefaultLifecycleProcessor
*/
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
/**
* 用于在此上下文中管理 bean 生命周期的生命周期处理器
*/
@Nullable
private LifecycleProcessor lifecycleProcessor;
/**
1. AbstractApplicationContext的方法
2. <p>
3. 为此上下文初始化生命周期处理器LifecycleProcessor
4. 如果上下文中未定义任何名为"lifecycleProcessor"的bean,则使用默认生命循环处理器DefaultLifecycleProcessor
*/
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//如果当前工厂包含名为"lifecycleProcessor"的bean
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
//那么通过getBean方法获取该bean实例,设置给lifecycleProcessor
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
if (logger.isTraceEnabled()) {
logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
}
}
//否则
else {
//新建一个DefaultLifecycleProcessor,设置给lifecycleProcessor
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
//手动注册到单例bean缓存中
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
if (logger.isTraceEnabled()) {
logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
}
}
}
5.3 onRefresh回调SmartLifecycle.start()方法
这属于容器生命周期的自动回调,关于SmartLifecycle我们在IoC学习的时候已经讲过了,在此不必赘述。
&emsp**;这一步就是找到全部的SmartLifecycle类型的bean,按照getPhase方法的返回值从小到大的回调它们的start方法。**
getLifecycleProcessor方法用于获取设置的生命周期处理器:
/**
5. AbstractApplicationContext的方法
6. <p>
7. 返回上下文使用的内部生命周期处理器。
8. 9. @return 内部生命周期处理器(从不null)
*/
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
if (this.lifecycleProcessor == null) {
throw new IllegalStateException("LifecycleProcessor not initialized - " +
"call 'refresh' before invoking lifecycle methods via the context: " + this);
}
return this.lifecycleProcessor;
}
onRefresh方法内部调用startBeans方法,autoStartupOnly传递参数为true,这个autoStartupOnly参数表示Lifecycle是否自动启动:
- 如果是新建ApplicationContext容器,在上下文刷新时会传递true,表示自启动所有的SmartLifecycle。
- 如果是手动调用容器的start()方法,那么传递false,表示手动启动所有的Lifecycle,包括SmartLifecycle。
通过下面的源码就能知道我们在IoC学习的时候说的“上下文刷新时自动启动的功能”是如何实现的。因为在上下文刷新时会传递true,会自启动所有的SmartLifecycle,而Lifecycle则不会启动,它们只会在手动调用容器的start()方法时才会启动。
/**
* DefaultLifecycleProcessor的方法
*/
@Override
public void onRefresh() {
//调用startBeans方法,传递参数为true
startBeans(true);
this.running = true;
}
/**
* DefaultLifecycleProcessor的方法
* <p>
* 启动所有Lifecycle类型的bean
*
* @param autoStartupOnly Lifecycle是否自动启动
* 如果是新建ApplicationContext容器,则是自启动所有的SmartLifecycle,传递true
* 如果是手动调用start方法,则是手动启动所有的Lifecycle,传递false
*/
private void startBeans(boolean autoStartupOnly) {
//获取所有的Lifecycle bean
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
//遍历
lifecycleBeans.forEach((beanName, bean) -> {
//如果不自动启动,或者(属于SmartLifecycle类型,并且支持自动启动)
//这表示如果是自启动则只会触发SmartLifecycle的启动,如果是手动启动则触发所有Lifecycle的启动
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
//返回当前bean组件的启动时间,SmartLifecycle默认返回DEFAULT_PHASE,Lifecycle默认返回0
int phase = getPhase(bean);
//存入phases中
LifecycleGroup group = phases.get(phase);
if (group == null) {
//创建LifecycleGroup
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
//加入到当前的group,一个group对应一个启动时间,同一个时间可以有多个bean
group.add(beanName, bean);
}
});
//如果phases不为null
if (!phases.isEmpty()) {
//获取所有启动时间的key
List<Integer> keys = new ArrayList<>(phases.keySet());
//从小到大排序,具有最低phase的对象首先启动
Collections.sort(keys);
for (Integer key : keys) {
//调用同一个group中所有的Lifecycle的start方法
phases.get(key).start();
}
}
}
/**
* 检索所有适用的Lifecycle bean,包括已创建的所有单例以及所有SmartLifecycle bean(即使它们被标记为lazy-init)。
*
* @return bean 的映射,以 bean 名称作为键,以 bean 实例作为值
*/
protected Map<String, Lifecycle> getLifecycleBeans() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
Map<String, Lifecycle> beans = new LinkedHashMap<>();
//获取所有Lifecycle类型的beanName数组beanNames,不包括非单例的bean,不允许初始化lazy-init单例以及FactoryBean创建的实例
String[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
//循环beanNames数组
for (String beanName : beanNames) {
//返回 bean 名称,必要时删除&引用前缀,并解析别名为规范名称。
String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);
//判断bean是否是FactoryBean类型
boolean isFactoryBean = beanFactory.isFactoryBean(beanNameToRegister);
//如果是FactoryBean,则加上&前缀
String beanNameToCheck = (isFactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
//如果(包含beanNameToRegister的单例bean,并且(不是FactoryBean类型,或者属于Lifecycle类型)),或者属于SmartLifecycle类型
if ((beanFactory.containsSingleton(beanNameToRegister) &&
(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||
matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)) {
//获取bean实例
Object bean = beanFactory.getBean(beanNameToCheck);
//如果不是当前调用者,并且属于Lifecycle类型,加入beans集合返回.
if (bean != this && bean instanceof Lifecycle) {
beans.put(beanNameToRegister, (Lifecycle) bean);
}
}
}
return beans;
}
5.3.1 AbstractApplicationContext.start
作为对比,我们看看容器的start()方法的源码。如下,可以看到是调用的DefaultLifecycleProcessor的start方法,内部的startBeans方法参数为false,即启动所有的Lifecycle包括SmartLifecycle。
/**
* AbstractApplicationContext的start方法
*/
@Override
public void start() {
//启动所有Lifecycle
getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}
/**
1. DefaultLifecycleProcessor的start方法
*/
@Override
public void start() {
//可以看到,这里传递的false,即启动所有的Lifecycle包括SmartLifecycle
startBeans(false);
this.running = true;
}
6 IoC容器初始化总结
本次主要接着上一篇文章,继续向下讲解finishBeanFactoryInitialization方法中的doCreateBean方法在createBeanInstance之后的源码,也就是bean的“初始化”过程,核心知识点包括:
applyMergedBeanDefinitionPostProcessors
方法,查找解析各种回调注解或者自动注入注解,为后面的属性注入和方法回调做准备,这是对注解的支持。populateBean
方法,填充通过createBeanInstance创建的bean实例,也就是XML或者注解的基于setter方法和字段反射进行属性注入过程;initializeBean
方法,对bean实例进行各种初始化回调,比如顺序回调所有设置的initMethod初始化方法,以及回调Aware接口的setter方法;registerDisposableBeanIfNecessary
方法,尝试通过解析注解或者XML注册bean销毁回调方法。
这几篇文章,总计约20万字
,我们终于讲完了ClassPathXmlApplicationContext 容器初始化的全部大概流程和重要的源码
,真是不容易呀!我们主要介绍的是IoC的部分的源码,其中夹杂着基于XML和基于部分注解的源码解析,而AOP、事务等其他知识的源码则没有介绍,下面我们对这几篇文章讲过的IoC容器的初始化过程进行简单的总结!
在IoC初始化过程中,核心的方法就是下面几个方法:
obtainFreshBeanFactory
——创建新BeanFactory工厂、读取、解析、加载 bean定义(BeanDefinition);invokeBeanFactoryPostProcessors
——初始化和回调BeanFactoryPostProcessor后处理器,用于对 BeanFactory进行扩展;registerBeanPostProcessors
——初始化和注册BeanPostProcessor后处理器,用于对bean进行扩展;finishBeanFactoryInitialization
——对所有非延迟加载(lazy-init)的普通单例 bean进行创建,包括bean初始化和实例化,以及途中的依赖注入和各种方法回调;
从上面几个核心方法也能看出来,IoC容器初始化的目的就是为了在启动容器时对bean定义进行一系列实例化和扩展操作。
在这几篇文章所讲的IoC容器初始化过程中,从头到尾所经历过的主要的扩展点调用顺序流程图如下
,主要就是refresh方法中的扩展点(点击查看大图):
到此,Spring ClassPathXmlApplicationContext IoC容器的大概初始化流程
全部结束。当然,还有很多的重要的知识点没有讲解:
- 某些标签的解析:< import/>、< alias/>、< context:property-placeholder/>等标签;
- 某些重要的后处理器的解析,比如最重要的ConfigurationClassPostProcessor后处理器,
- AOP、事物、异步任务、调度任务、事件发布等扩展知识;
- 一些总结性的知识,比如循环依赖、Aware接口等等。
这些知识,我们到后面的文章中将会单独讲解!
相关文章:
https://spring.io/
Spring 5.x 学习
Spring 5.x 源码
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!