spring中常用的BeanPostProcessor(下)

接着上篇文章继续讲述,本篇主要讲述SmartInstantiationAwareMergedBeanDefinition后处理器的源码解析和使用。在复习下这张类图:
spring中常用的BeanPostProcessor(下)_第1张图片
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 执行结果
spring中常用的BeanPostProcessor(下)_第2张图片执行的初始化方法,已变成MergedBeanDefinition后处理器修改后的方法了。

MergedBeanDefinitionPostProcessor应用结论

  • postProcessMergedBeanDefinition:在解析bean属性之前执行,一般用于修改BeanDefinition信息。

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 执行结果
spring中常用的BeanPostProcessor(下)_第3张图片SmartInstantiationAwareBeanPostProcessor应用结论

  • getEarlyBeanReference:在bean循环依赖场景中,beanA获取提前曝光的beanB时调用。

你可能感兴趣的:(spring源码)