Spring 源码解析——IOC 源码解析(BeanPostProcessor 系列之体系概述)(六)

写文章不易,转载请标明出处。

同时,如果你喜欢我的文章,请关注我,让我们一起进步。

一、概述

在前面的 BeanPostProcessor 系列博文中我们已经对几个常用的 BeanPostProcessor 实现类的源码进行了解析,但是在分析的过程中我慢慢的发现因为缺少对 BeanPostProcessor 整个体系的认知和了解,导致对每一个 BeanPostProcessor 实现类的解析都总是觉得差一点东西,感觉没有能够分析的很透彻,同时还存在的一个问题就是因为我们都是对单个的 BeanPostProcessor 实现类进行分析,这样导致的问题就是我们没有办法将它们关联起来,好像每一部分都是分离开的,但其实对于 Spring 来说 BeanPostProcessor 是伴随着 Bean 整个生命周期的组件。

因此,借着小长假的空闲时间,特意在查询了一些资料并在经过了几次调试和思考后大致确定了 BeanPostProcessor 的一个比较完整的调用流程,通过源码的阅读和调试我大概确定了 Spring 当中对于五个主要 BeanPostProcessor 的九处调用,这九处调用贯穿了 Bean 的整个生命周期。因为这篇博文是一个比较流程化的解析博文,重在让读者能够对 Spring 当中的 BeanPostProcessor 整体有一个相对比较清晰的认识,所以在这篇博文中不会涉及到特别多的源码(仅存的一些源码是涉及 BeanPostProcessor 的相关接口,主要是为了能够让大家对 BeanPostProcessor 中方法的入参和返回值有一个比较清晰地认识),更多地会是以流程图和文字分析的方式来展现。

 

二、功能介绍

对于 BeanPostProcessor 大家一定都不陌生了,这个接口贯穿了 Bean 的整个生命周期,为系统内部的组件和外部的开发者而都提供了一个干预 Bean 生命周期的渠道,在 BeanPostProcessor 顶层接口中主要涉及的是 Bean 生命周期中初始化的部分,而在其扩展接口中分别又涉及了实例化和属性注入等一系列部分。并且在 Spring 当中许多重要的功能比如自动装配、AOP 以及 Java 配置类等都是通过 BeanPostProcessor 来实现的,所以说 BeanPostProcessor 可以算是 Spring 当中的一大核心组件。

但是 BeanPostProcessor 复杂的集成体系以及种类繁多的实现类让我们眼花缭乱,因此我们在接下来会首先梳理 Bean 生命周期中 BeanPostProcessor 的九处具体调用,然后再去详细的分析五个重要的 BeanPostProcessor 接口的方法及其作用。

 

三、生命周期整体调用流程

四、主要接口解析

4.1 整体结构体系

4.2 BeanPostProcessor 

public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

BeanPostProcessor 接口是下面所述的所有接口的顶层接口,它提供的工厂钩子函数允许自定义修改新的 Bean 实例,例如 检查标记接口使用代理类包装它们。ApplicationContexts 可以在其 BeanDefinition 中自动检测 BeanPostProcessor Bean,并将其应用于随后创建的所有 Bean 实例。普通 BeanFactory 允许对 BeanPostProcessor(后置处理器)进行程序化注册,适用于通过该工厂创建的所有 Bean 实例,并且通常通过标记接口等填充 Bean 的 BeanPostProcessor 将实现 postProcessBeforeInitialization 回调方法,而使用代理类包装 Bean 的 BeanPostProcessor 通常将实现 postProcessBeforeInitialization 回调方法。 

对于 postProcessBeforeInitialization 方法,它会在所有的 Bean 初始化回调方法(例如 InitializingBean 的 afterPropertiesSet 或自定义的初始化方法)之前被调用,作用于已经完成属性值填充的给定 Bean 实例,它默认返回的是原始 Bean 实例,但也可以返回包装后的 Bean 实例。

postProcessAfterInitialization 方法将在所有 Bean 初始化回调方法(例如 InitializingBean 的 afterPropertiesSet 或自定义的init-method)之后被调用,作用于已经完成属性值填充的给定 Bean 实例,它默认返回的是原始 Bean 实例,但也可以返回包装后的 Bean 实例。对于 FactoryBean,将为 FactoryBean 实例和由 FactoryBean 创建的对象(从Spring 2.0开始)调用此回调(后置处理器可以通过相应的 bean instanceof FactoryBean 检查来确定是应用到 FactoryBean 还是创建的对象,还是两者都应用)。与所有其他 BeanPostProcessor 回调相比,此回调还将在 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法触发短路(方法返回值不为 null)后被调用。

4.3 MergedBeanDefinitionPostProcessor

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

	default void resetBeanDefinition(String beanName) {}
}

 MergedBeanDefinitionPostProcessor 是 BeanPostProcessor 接口的一个实现接口,它是在运行时用于合并 BeanDefinition 的回调接口。实现此子接口可以对 Spring 中 BeanFactory 创建的 Bean 实例的 MergedBeanDefinition(原始 BeanDefinition 的已处理副本,存放在 BeanFactory 的 mergedBeanDefinitions 集合中)进行处理。 例如通过 postProcessMergedBeanDefinition 方法可以内省 BeanDefinition,以便在对 Bean 的实际实例进行处理之前准备一些缓存的元数据,并且其还允许修改 BeanDefinition ,但只允许修改实际用于并行修改的 Definition 属性,因此本质上这仅适用于在 RootBeanDefinition 中定义的操作而不适用于其基类的属性。

postProcessMergedBeanDefinition 这个方法的作用简单明了,就是对指定 Bean 的给定的 MergedBeanDefinition 进行处理。而 resetBeanDefinition 方法就是起到一个通知的作用,即通知给定的 BeanName 所对应的 BeanDefinition 已经被重新设置,所以此 BeanPostProcessor(后置处理器)应清除受影响的 Bean 的所有元数据,其默认实现为空。

4.4 InstantiationAwareBeanPostProcessor

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
		return null;
	}

	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
		return pvs;
	}
}

 InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 一个比较重要的实现接口,因为在这个接口中对 BeanPostProcessor 的作用范围进行了扩展,从只关注 Bean 的初始化扩展到了可以关注 Bean 的实例化(添加了实例化之前和实例化之后显式设置属性或自动装配之前的回调),通常用于禁止特定目标 Bean 的默认实例化,例如使用特殊 TargetSources 创建代理( 合并目标,延迟初始化目标等)或实施其他注入策略(例如属性注入)。

但是需要注意的是这个接口是一个专用接口,主要供框架内部使用,所以根据 Spring 的建议应尽可能实现普通的顶层 BeanPostProcessor 接口或从 InstantiationAwareBeanPostProcessorAdapter 派生来避免对该接口进行扩展。同时在这个接口规定了四个方法,其中最重要的两个就是 postProcessBeforeInstantiation 和 postProcessAfterInstantiation 方法,这两个方法分别会在 Bean 实例化之前和之后进行回调,然后剩下的两个方法会在开始设置实例的属性之前进行回调。

postProcessBeforeInstantiation 的作用时机是在实例化目标 Bean 之前,其返回的 Bean 对象可以是代替原目标 Bean 使用的代理 Bean 对象,从而有效地抑制了目标 Bean 的默认实例化。如果此方法返回一个非空(null)对象,则 Bean 创建过程将被短路,接下来唯一调用的进一步处理的方法是自定义配置的 BeanPostProcessor 的 postProcessAfterInitialization 回调(这点可见下面的源码)。此回调将应用于具有其 Bean 类(BeanClass)的 Bean 定义(BeanDefinition)以及工厂方法定义(factory-method definitions),在这种情况下返回的 Bean 类型将在此处传递。同时自定义的 BeanPostProcessor 可能实现扩展的 SmartInstantiationAwareBeanPostProcessor 接口,以便预测它们将在此处返回的 Bean 对象的类型。 最后再次强调,该方法的默认实现返回 null ,此时继续进行默认实例化流程,也可以返回要公开的 Bean 对象(例如自己创建的代理 Bean 对象)而不是原目标 Bean 的默认实例来替换掉原目标 Bean 对象。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		// Make sure bean class is actually resolved at this point.
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
                                // 调用 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                                // 如果 postProcessBeforeInstantiation 返回不为 null
				if (bean != null) {
                                        // 紧接着调用 BeanPostProcessor 的 postProcessAfterInitialization 方法
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

postProcessAfterInstantiation 方法会在通过构造函数或工厂方法进行实例化 Bean 之后且在发生 Spring 属性填充(通过显式属性或自动装配)之前执行,这是在 Spring 自动装配(属性注入)开始之前对给定 Bean 实例执行自定义属性注入的理想回调。该方法正常情况下默认实现返回 true ,表示应该为 Bean 进行属性填充,反之如果返回 false 则意味着应当跳过属性注入,并且将阻止对此 Bean 实例调用任何后续的 InstantiationAwareBeanPostProcessor 实例方法。

postProcessProperties 这个方法是 postProcessPropertyValues 的一个最新版本的替换方法,因为在下面我们可以看到 postProcessPropertyValues 方法已经将要被废弃了。这个方法会作用在 Spring 为属性进行注入之前,对给定的属性值进行最后处理,并且无需使用属性描述符。但如果实现类提供了自定义的 postProcessPropertyValues 方法的实现,则实现类中的此方法应返回 null(默认值),此时会继续尝试调用 postProcessPropertyValues 方法,否则返回 pvs(处理后的属性值),且在此接口的将来版本中(删除了 postProcessPropertyValues)默认实现将直接按原样返回给定的 pvs(PropertyValues 属性值),这点目前也可以从下面的源码中求证。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	...
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                // 首先尝试调用 postProcessProperties 方法
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                                // 如果获取到的 postProcessProperties 方法返回值为空
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
                                        // 则再调用 postProcessPropertyValues 方法
					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
	}
	...
}

postProcessPropertyValues 方法正如其注解所述是一个将要被废弃的方法,它的功能跟上面的  postProcessProperties 是相似的,也是在 Spring 进行属性注入之前对属性值进行最后的处理,它允许检查 Bean 属性是否满足所有依赖关系,例如基于 Bean 属性设置的 setter 上的 @Required 注解,还允许替换要应用的属性值,通常是通过基于原始 PropertyValues 创建新的 MutablePropertyValues 实例,添加或删除特定值来实现。它的返回值是应用于给定 Bean 的实际属性值(可以是传入的 PropertyValues 实例,也可以是我们修改后的属性实例)或者返回 null 来跳过属性填充。

4.5 SmartInstantiationAwareBeanPostProcessor

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {

		return null;
	}

	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

 首先 SmartInstantiationAwareBeanPostProcessor 是 InstantiationAwareBeanPostProcessor 的一个实现接口,也就是可以理解为它是 InstantiationAwareBeanPostProcessor 接口的扩展,相对于父接口它添加了一个用于预测已处理 Bean 最终类型的回调方法 predictBeanType 。但是需要注意的是此接口是一个专用接口主要供框架内部使用,通常应用程序提供的后置处理器应仅实现简单的 BeanPostProcessor 接口或从 InstantiationAwareBeanPostProcessorAdapter 类进行派生。最后,在下一个发行版中,新的方法可能会被添加到此接口。

predictBeanType 方法预测最终从 postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor 中的回调方法)回调返回的 Bean 的类型,其默认实现返回 null 。determineCandidateConstructors 方法用于确定实例化给定 Bean 的候选构造函数(一般用于实例化 Bean 之前),此方法默认实现也返回 null 。

getEarlyBeanReference 方法主要是用来解决单例 Bean 循环依赖的问题(解决方案分析在前面的博文中),这个方法的直观作用就是通过给定的 BeanName 在允许暴露未实例化完成的 Bean 的条件下获取 Bean 的引用,这个接口给 BeanPostProcessor 一个机会去获取早期包装 Bean(未完全实例化完成的 Bean)。 

4.6 DestructionAwareBeanPostProcessor

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

	void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

	default boolean requiresDestruction(Object bean) {
		return true;
	}
}

 DestructionAwareBeanPostProcessor 接口仅实现了一个父接口即 BeanPostProcessor,这个接口主要是为 Bean 的生命周期中添加了销毁前的回调,典型用法是在特定的 Bean 类型上调用自定义销毁回调,并与相应的初始化回调匹配。在这个接口中存在两个方法 postProcessBeforeDestruction 和 requiresDestruction 。

postProcessBeforeDestruction 方法的主要作用是在销毁实例之前,将此 BeanPostProcessor 应用于给定的 Bean 实例,例如调用自定义销毁回调。就像 DisposableBean 接口的 destroy 方法和自定义的 destroy 方法(通过 Java 注解类和 XML 配置的 destroy 方法)一样,此回调仅适用于容器完全管理其生命周期的 Bean, 单例和作用域 Bean 通常是这种情况。

requiresDestruction 方法的主要作用是判断给定的 Bean 实例是否需要被此 BeanPostProcessor 销毁,默认实现返回 true, 且在 Spring 5 之前如果 DestructionAwareBeanPostProcessor 的实现类未提供此方法的具体实现,则 Spring 也会默认假定返回 true 。所以总结来说,如果最终应为此 Bean 实例调用 postProcessBeforeDestruction 方法则返回 true,如果不需要则返回 false 。

 

五、内容总结

最后来对这篇博文进行一下总结,通过这篇博文我们对 BeanPostProcessor 的体系结构进行了一个整体的分析,首先我们通过流程图来列举了 Spring 当中 BeanPostProcessor 的九处调用点(因为流程图中就已经很清晰的描述了 BeanPostProcessor 在 Bean 生命周期中的调用流程,所以这篇博文没有过多的源码分析),然后我们依次对 Spring 当中比较重要的 BeanPostProcessor 以及其子接口进行详细的分析,基本捋清了几个必要重要的 BeanPostProcessor 系列接口及其方法的作用。通过这次对 BeanPostProcessor 整体源码的阅读,能够让我们更加清晰地了解 Bean 的整个生命周期,也为后续的对 BeanPostProcessor 实现类及其它生命周期回调方法的分析打下了比较好的基础。

在你想要放弃的时候,想想是什么让你当初坚持走到了这里。

发布了244 篇原创文章 · 获赞 32 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_40697071/article/details/102053260
今日推荐