0
点赞
收藏
分享

微信扫一扫

Spring系列:BeanFactoryPostProcessor和BeanPostProcessor

晚熟的猫 2022-01-08 阅读 141
springioc

参考资料:

《Spring的BeanFactoryPostProcessor和BeanPostProcessor》

 《Spring IoC源码学习:invokeBeanFactoryPostProcessors 详解》

 《Spring IoC源码学习:registerBeanPostProcessors 详解》

写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。

在学习IOC的过程中,发现对于BeanFactoryPostProcessor(实例工厂后置处理器)和BeanPostProcessor(实例后置处理器)之间的关系存在一些疑问,这里结合查到的几份资料整理了一下。

一、简单概括

                这两个接口,都是Spring初始化bean时对外暴露的扩展点。两个接口名称看起来很相似,但作用及使用场景却不同。

        1、BeanFactoryPostProcessor

                BeanFactoryPostProcessor是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。该接口只有一个postProcessBeanFactory方法,在bean初始化前调用。

public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

        

        2、 BeanPostProcessor

                BeanPostProcessor接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。该接口有两个方法,postProcessBeforeInitialization和postProcessAfterInitialization,都是在bean初始化后调用,区别在于

public interface BeanPostProcessor {

	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

       

        3、异同

                简单总结一下,就是BeanFactoryPostProcessor和BeanPostProcessor都是Spring初始化时提供的扩展点,即我们可以通过实现这两个接口实现对bean的修改。区别在于,前者是对BeanFactory(即bean的定义,bean definitions的扩展,在bean初始化前调用,后者是对bean (即实例对象)的扩展,在bean初始化后调用。

二、使用示范

        下面,使用xml配置的方式调用自定义接口配置

        1、myTestBean

             这里加了2个初始化相关参数,作为补充

                (1)afterPropertiesSet

                        接口InitializingBean定义的方法,在初始化过程自动中被调用

                (2)initMethod

                        xml配置方式中,可在bean属性中设置init-method="initMethod"指定,作用同上

public class MyTestBean implements InitializingBean
{
    private String value1;
    private String value2;
    
    public MyTestBean() {
        System.out.println("===调用构造方法===");
    }
    
    public String getValue1() {
        return value1;
    }
    public void setValue1(String value1) {
        System.out.println("===调用setValue1方法===");
        this.value1 = value1;
    }
    public String getValue2() {
        return value2;
    }
    public void setValue2(String value2) {
        System.out.println("===调用setValue2方法===");
        this.value2 = value2;
    }
    public void afterPropertiesSet() throws Exception {
        System.out.println("===调用afterPropertiesSet方法===");
    }
    public void initMethod() {
        System.out.println("===调用initMethod方法===");
    }
    public String toString() {
        StringBuilder builder = new StringBuilder();
        System.out.println("value1="+this.value1);
        System.out.println("value2="+this.value2);
        return builder.toString();
    }

}

        2、MyBeanFactoryPostProcessor

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        
        BeanDefinition bd = beanFactory.getBeanDefinition("myTestBean");
        if(bd!=null){
            System.out.println("===调用MyBeanFactoryPostProcessor的postProcessBeanFactory===");
            System.out.println("===获取myTestBean的作用域:"+bd.getScope());
            bd.setScope("singleton");
            System.out.println("===修改myTestBean的作用域:"+bd.getScope());
            MutablePropertyValues pv =  bd.getPropertyValues();  
            if (pv.contains("value2")) {  
                System.out.println("===在BeanFactoryPostProcessor中修改value2的值为:参数值n===");
                pv.addPropertyValue("value2", "参数值n");  
            }  
        }
        
    }
 
}

        3、MyBeanPostProcessor

public class MyBeanPostProcessor implements BeanPostProcessor {
    
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if("myTestBean".equals(beanName)){
            System.out.println("===调用postProcessBeforeInitialization方法,"+beanName);
        }
        return bean;
    }
    
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("myTestBean".equals(beanName)){
            System.out.println("===调用postProcessAfterInitialization方法,"+beanName);
        }
        return bean;
    }
}

        4、springContext.xml

	<bean id="myTestBean" class="com.test.MyTestBean" init-method="initMethod"
		scope="prototype">
		<property name="value1" value="参数值1" />
		<property name="value2" value="参数值2" />
	</bean>
	
	<bean id="myBeanPostProcessor" class="com.test.MyBeanPostProcessor" />
	<bean id="myBeanFactoryPostProcessor" class="com.test.MyBeanFactoryPostProcessor" />

        5、Test类

public class myTest
{
    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springContext.xml");
        MyTestBean bean = (MyTestBean) context.getBean("myTestBean");
        System.out.println("===============下面输出结果============");
        System.out.println("value1=" + bean.getValue1());
        System.out.println("value2=" + bean.getValue2());

    }
}

        6、结果展示

===调用MyBeanFactoryPostProcessor的postProcessBeanFactory===
===获取myTestBean的作用域:prototype
===修改myTestBean的作用域:singleton
===在BeanFactoryPostProcessor中修改value2的值为:参数值n===
===调用构造方法===
===调用setValue1方法===
===调用setValue2方法===
===调用postProcessBeforeInitialization方法,myTestBean
===调用afterPropertiesSet方法===
===调用initMethod方法===
===调用postProcessAfterInitialization方法,myTestBean
===============下面输出结果============
value1=参数值1
value2=参数值n

                我们可以看到调用过程如下

三、补充

       1、关于执行顺序

        我们知道BeanFactoryPostProcessor————>初始化————>BeanPostProcessor

        在上面的例子里,在BeanFactoryPostProcessor中对bena的value2的值做了修改,这就属于对bean的修改,但不推荐,原因后面会讲。同时也对scope做了修改,将多例变为了单例,这就属于bean Factory的修改,是BeanFactoryPostProcessor真正应该起作用的地方。

        2、不推荐BeanFactoryPostProcessor中对bean的修改

           主要有以下2方面原因                

                (1)处在调用链的最顶端

                   由于BeanFactoryPostProcessor在调用链的最顶端,这导致后面的修改都有可能将BeanFactoryPostProcessor中对bean的修改覆盖掉,但BeanFactory只能在这里修改,所以不用担心BeanFactory的改动被覆盖。

                (2)无法使用自动注入

                    这里我们需要简单看一下bean实例化的核心方法AbstractApplicationContext中的refresh调用过程

    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);

                   这里会先调用invokeBeanFactoryPostProcessors,实例化和调用所有 BeanFactoryPostProcessor,然后调用registerBeanPostProcessors,注册所有的BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。

                  然而,@AutoWired和@Resource都是依赖于BeanPostProcessor的实现类。BeanFactoryPostProcessor执行时@AutoWired和@Resource还未注册,,无法使用自动注入功能来修改bean。因此,只能通过配置xml的方式来实现,在大型项目中,这必然是无法接受的,所以不推荐在BeanFactoryPostProcessor中修改bean

        

举报

相关推荐

0 条评论