接着上篇文章继续讲述,本篇主要讲述SmartInstantiationAware和MergedBeanDefinition后处理器的源码解析和使用。在复习下这张类图:
1. MergedBeanDefinitionPostProcessor的应用
MergedBeanDefinition后处理器处理具备基本的BeanPostProcessor功能,还可以用于修改BeanDefinition,执行时机是在创建bean之后,解析bean属性之前。
1.1 源码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 创建bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 2. 允许MergedBeanDefinition后处理器修改BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 3. 提前曝光bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 4. 填充bean
populateBean(beanName, mbd, instanceWrapper);
// 5. 调用bean的初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 省略无关代码...
return exposedObject;
}
该代码来自于AbstractAutowireCapableBeanFactory类的doCreateBean方法,跟bean初始化的代码基本都在这个类中。代码结构还算清晰,可以看出在创建bean之后调用了applyMergedBeanDefinitionPostProcessors。点进去看看
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
// 合并BeanDefinition后处理
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
其实就是调用了MergedBeanDefinition后处理器的postProcessMergedBeanDefinition方法。
1.2 验证
目的:使用MergedBeanDefinition后处理器修改一个bean的初始化方法。
1.2.1 创建一个Department类
@Data
public class Department {
private Integer id;
private String name;
public Department() {
System.out.println("执行department构造方法...");
}
public void testInitMethod(){
System.out.println("我是配置的初始化方法...");
}
public void mergedInitMethod(){
System.out.println("我是修改后的初始化方法...");
}
}
department有两个自定义的方法:testInitMethod和mergedInitMethod
1.2.2 配置bean的初始化方法
<context:component-scan base-package="com.kaka.spring.beans.factory.config" />
<bean id="department" class="com.kaka.spring.pojo.Department" init-method="testInitMethod">
<property name="id" value="22"/>
<property name="name" value="技术部"/>
bean>
1.2.3 使用MergedBeanDefinition后处理器修改bean指定的初始化方法
@Component
public class MyMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
/**
* 创建bean之后,填充属性之前执行。
* 一般用于根据beanDefinition中属性执行自定义逻辑,或者修改beanDefinition
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 因为每个bean都会执行该方法,我们只处理beanName为department的实例
if ("department".equals(beanName)) {
String initMethodName = beanDefinition.getInitMethodName();
System.out.println(">>>mergedBeanDefinition后处理器执行...");
System.out.println(">>>原来的初始化方法为:" + initMethodName);
// 修改初始化方法为mergedInitMethod
beanDefinition.setInitMethodName("mergedInitMethod");
}
}
}
1.2.4 执行
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Department bean = classPathXmlApplicationContext.getBean("department", Department.class);
System.out.println(bean);
}
1.2.5 执行结果
执行的初始化方法,已变成MergedBeanDefinition后处理器修改后的方法了。
MergedBeanDefinitionPostProcessor应用结论:
2. SmartInstantiationAwareBeanPostProcessor应用
SmartInstantiationAware后处理器用在bean循环依赖的场景,当一个bean使用到另一个提前曝光的bean的时候调用。
2.1 源码
摘取AbstractAutowireCapableBeanFactory类的doCreateBean方法代码片段,上面提到过。省略无关代码:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 创建bean
// 2. 允许MergedBeanDefinition后处理器修改BeanDefinition
// 3. 提前曝光bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 提前曝光的bean,使用时会调用getEarlyBeanReference方法
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 4. 填充bean
populateBean(beanName, mbd, instanceWrapper);
// 5. 调用bean的初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略无关代码...
return exposedObject;
}
提前曝光的bean保存在DefaultSingletonBeanRegistry类的singletonFactories属性,是一个HashMap结构。
bean的循环依赖场景,需要使用到提前曝光的bean,此时就会从singletonFactories中获取,进而调用getEarlyBeanReference方法。
下面就看看这个getEarlyBeanReference方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// SmartInstantiationAware后处理器的提前获取bean方法
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
2.2 验证
2.2.1 创建循环依赖的类:A依赖B,B依赖C,C依赖A
@Data
public class TestA {
private TestB testB;
}
@Data
public class TestB {
private TestC testC;
}
@Data
public class TestC {
private TestA testA;
}
2.2.2 配置bean
<bean id="testA" class="com.kaka.spring.pojo.circular.TestA" >
<property name="testB" ref="testB"/>
bean>
<bean id="testB" class="com.kaka.spring.pojo.circular.TestB">
<property name="testC" ref="testC"/>
bean>
<bean id="testC" class="com.kaka.spring.pojo.circular.TestC">
<property name="testA" ref="testA"/>
bean>
<context:component-scan base-package="com.kaka.spring.beans.factory.config" />
2.2.3 创建一个实现SmartInstantiationAwareBeanPostProcessor的后处理器
@Component
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
System.out.println("循环依赖的bean,提前获取的beanName:" + beanName);
return bean;
}
}
因为TestA初始化依赖TestB,所以加载TestB;
TestB初始化又依赖TestC,所以加载TestC;
TestC初始化依赖TestA,发现TestA也在创建中,就会去DefaultSingletonBeanRegistry类的singletonFactories属性中获取提前曝光的TestA(此时的TestA已创建完成,只是还没有初始化),进而有机会调用到SmartInstantiationAware后处理器。
2.2.4 执行代码
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
// 不要输出TestA,因为三个类互相依赖,tostring方法输出会造成死循环
// 如果想输出可以改下其中一个类的toString方法
}
2.2.5 执行结果
SmartInstantiationAwareBeanPostProcessor应用结论: