Spring源碼解析(十四)-BeanPostProcessor

Spring版本

5.2.5.RELEASE

參考

《芋道源碼》

源碼解讀

在bean的創(chuàng)建流程中,可以看到諸多BeanPostProcessor的諸多應用,那么,BeanPostProcessor究竟是個怎樣的神奇的存在呢?

BeanPostProcessor

public interface BeanPostProcessor {

    /**
     * Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method). The bean will already be populated with property values.
     * The returned bean instance may be a wrapper around the original.
     * <p>The default implementation returns the given {@code bean} as-is.
     * @param bean the new bean instance
     * @param beanName the name of the bean
     * @return the bean instance to use, either the original or a wrapped one;
     * if {@code null}, no subsequent BeanPostProcessors will be invoked
     * @throws org.springframework.beans.BeansException in case of errors
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method). The bean will already be populated with property values.
     * The returned bean instance may be a wrapper around the original.
     * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
     * instance and the objects created by the FactoryBean (as of Spring 2.0). The
     * post-processor can decide whether to apply to either the FactoryBean or created
     * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
     * <p>This callback will also be invoked after a short-circuiting triggered by a
     * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
     * in contrast to all other {@code BeanPostProcessor} callbacks.
     * <p>The default implementation returns the given {@code bean} as-is.
     * @param bean the new bean instance
     * @param beanName the name of the bean
     * @return the bean instance to use, either the original or a wrapped one;
     * if {@code null}, no subsequent BeanPostProcessors will be invoked
     * @throws org.springframework.beans.BeansException in case of errors
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     * @see org.springframework.beans.factory.FactoryBean
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

通過源碼注釋可以看到,postProcessBeforeInitialization提供了一個途徑去修改一個已經(jīng)實例化的bean,但這個修改是發(fā)生在填充屬性之后初始化bean之前的,而返回值則可能是一個對原始bean進行過包裝后的bean。
postProcessBeforeInitialization不同的是,postProcessAfterInitialization發(fā)生在填充屬性之后且初始化bean之后。
倆者的不同點在于是否初始化bean,這從方法名上其實也可以看出來,下面,通過demo具體演示一下如何通過BeanPostProcessor修改bean的屬性

Demo

Student

public class Student {

    private String id;

    private String name;

    private String desc;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

BeanProcessorsTest

public class BeanProcessorsTest implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization");
        if (bean instanceof Student) {
            ((Student) bean).setId("id set by postProcessBeforeInitialization");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization");
        if (bean instanceof Student) {
            ((Student) bean).setName("name set by postProcessAfterInitialization");
        }
        return bean;
    }

}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="beanProcessorsTest" class="com.kungyu.custom.element.BeanProcessorsTest"/>

    <bean id="student" class="com.kungyu.custom.element.Student">
        <property name="name" value="name"/>
        <property name="id" value="id"/>
    </bean>
</beans>

測試

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        BeanProcessorsTest beanProcessorsTest = (BeanProcessorsTest) context.getBean("beanProcessorsTest");

        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
        System.out.println(student.getId());

    }
}

結果

結果

可以看到,在spring.xml文件中設置的idname倆者的初始值已經(jīng)被覆蓋成BeanProcessorsTest中設置的值

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容