Spring源碼解讀『Bean擴展接口』

上篇文章我們介紹了Spring Bean的初始化流程,在最後我們提到在通過populateBean方法調用後,調用了initializeBean方法,實現了一些列例如BeanNameAwareBeanPostProcessor等擴展接口的調用,本篇文章我們就來看一下Spring提供給開發者的一些擴展接口。

Spring框架運用了非常多的設計模式,從整體上看,它的設計嚴格遵循了OCP——開閉原則:

  • 對修改關閉,外部無法修改Spring整個運作的流程
  • 對擴展開放,可以通過繼承、實現Spring提供的衆多抽象類與接口來改變類加載的行爲

本篇文章介紹的擴展接口就體現了對擴展開放的原則。

1. InitializingBean&DisposableBean

InitializingBean接口中提供了方法afterPropertiesSet(),DisposableBean接口中提供了方法destroy()。這兩個接口功能類似,InitializingBean接口的afterPropertiesSet()方法用於Bean屬性設置完畢(在invokeInitMethods方法中調用),做一些初始化操作。DisposableBean接口的destroy()方法用於Bean生命週期結束前(DefaultSingletonBeanRegistry的destroyBean方法調中調用)做一些收尾工作。

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
	void destroy() throws Exception;
}

下面我們來看一個示例:

public class TestBean implements InitializingBean, DisposableBean {

    private String testName;

    public void setTestName(String testName) {
        System.out.println("Call TestBean.setName()");
        this.testName = testName;
    }


    public void destroy() throws Exception {
        System.out.println("Call TestBean.destroy(), DisposableBean");
    }


    public void afterPropertiesSet() throws Exception {
        System.out.println("Call TestBean.afterPropertiesSet(), InitializingBean");
    }

    public void initMethod() {
        System.out.println("Call TestBean.initMethod(), init-method");
    }

    public void destroyMethod() {
        System.out.println("Call TestBean.destroyMethod(), destroy-method");
    }
}
<?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-4.1.xsd">
    <bean id="testBean" class="com.zhuoli.service.spring.explore.extend.TestBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="testName" value="testName"/>
    </bean>
</beans>
public class SpringExtendsTest {
    public static void main(String[] args) {
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-extends.xml");
        TestBean testBean = (TestBean) applicationContext.getBean("testBean");

        applicationContext.close();
    }
}

執行結果:

Call TestBean.setName()
Call TestBean.afterPropertiesSet(), InitializingBean
Call TestBean.initMethod(), init-method
Call TestBean.destroy(), DisposableBean
Call TestBean.destroyMethod(), destroy-method

可以看到執行順序爲set方法、InitializingBean的afterPropertiesSet方法、bean init-method指定的初始化方法、DisposableBean的destroy方法、bean的destroy-method指定的銷燬方法

其實也好解釋,通過上一篇文章我們知道setName方法是在populateBean方法中調用的,所以最先調用。InitializingBean的afterPropertiesSet方法是通過populateBean後面的方法initializeBean中調用的invokeInitMethods中調用的,並且調用在init-method之前,所以之後InitializingBean的afterPropertiesSet方法會被調用,接着纔是init-method。

關於這幾個接口,這裏總結幾點:

  • InitializingBean接口、Disposable接口可以和Bean的屬性init-method、destory-method配合使用,接口的優先級大於Bean的屬性
  • InitializingBean接口、Disposable接口方法的調用底層使用類型強轉.方法名()進行直接方法調用,init-method、destory-method底層使用反射,前者和Spring耦合程度更高但效率高,後者解除了和Spring之間的耦合但是效率低(關於效率高低,這點不好講,只是“理論之談,反射也並不一定就比直接方法調用效率低很多。至於使用哪種方式,純憑個人喜好)
  • afterPropertiesSet()方法是在Bean的屬性設置之後纔會進行調用,某個Bean的afterPropertiesSet()方法執行完畢纔會執行下一個Bean的afterPropertiesSet()方法,因此不建議在afterPropertiesSet()方法中寫處理時間太長的方法

2. Aware接口

這裏我們介紹BeanNameAware、ApplicationContextAware和BeanFactoryAware這三個Aware相關的接口。Aware的意思是”感知的”,顧名思義,這三個接口的意思也與“感知”相關。

  • 實現BeanNameAware接口的Bean,可以在Bean加載的過程中獲取該Bean的id
  • 實現ApplicationContextAware接口的Bean,可以在Bean加載的過程中獲取Spring的上下文ApplicationContext,從ApplicationContext中可以獲取包括任意的Bean以及大量Spring容器內容和信息
  • 實現BeanFactoryAware接口的Bean,可以在Bean加載的過程中獲取加載該Bean的BeanFactory

下面來看個例子:

public class AwareBean implements InitializingBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware {

    private String beanName;
    private ApplicationContext applicationContext;
    private BeanFactory beanFactory;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Call AwareBean.afterPropertiesSet(), InitializingBean");
    }

    public void setBeanName(String beanName) {
        System.out.println("Call AwareBean.setBeanName(), beanName = " + beanName);
        this.beanName = beanName;
    }


    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("Call AwareBean.setApplicationContext(), applicationContext = " + applicationContext);
        this.applicationContext = applicationContext;
    }


    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Call AwareBean.setBeanFactory(), beanFactory = " + beanFactory);
        this.beanFactory = beanFactory;
    }
}
<?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-4.1.xsd">
    <bean id="awareBean" class="com.zhuoli.service.spring.explore.aware.AwareBean" />
</beans>
public class AwareBeanTest {
    public static void main(String[] args) {
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-aware.xml");
        AwareBean awareBean = (AwareBean) applicationContext.getBean("awareBean");

        applicationContext.close();
    }
}

執行結果:

Call AwareBean.setBeanName(), beanName = awareBean
Call AwareBean.setBeanFactory(), beanFactory = org.springframework.beans.factory.support.DefaultListableBeanFactory@7a187f14: defining beans [awareBean]; root of factory hierarchy
Call AwareBean.setApplicationContext(), applicationContext = org.springframework.context.support.ClassPathXmlApplicationContext@7e32c033, started on Thu Apr 16 09:01:20 CST 2020
Call AwareBean.afterPropertiesSet(), InitializingBean

關於這三個接口,總結幾點:

  • 如果你的BeanName、ApplicationContext、BeanFactory有用,那麼就自己定義一個變量將它們保存下來(如上面的成員變量beanName、applicationContext、beanFactory)。如果沒用,那麼只需要實現setXXX()方法,用一下Spring注入進來的參數即可
  • 如果Bean同時還實現了InitializingBean,容器會保證BeanName、ApplicationContext和BeanFactory在調用afterPropertiesSet()方法前被注入,也就是說Aware接口的優先級大於InitializingBean接口

3. FactoryBean

傳統的Spring容器加載一個Bean的整個過程,都是由Spring控制的,開發者除了設置Bean相關屬性之外,是沒有太多的自主權的。FactoryBean改變了這一點,開發者可以個性化地定製自己想要實例化出來的Bean,方法就是實現FactoryBean接口。下面來看個例子:

public interface Car {
    public void driving();
}
public class Bmw implements Car {
    @Override
    public void driving() {
        System.out.println("Bmw driving");
    }
}
public class Benz implements Car {
    @Override
    public void driving() {
        System.out.println("Benz driving");
    }
}
public class CarFactoryBean implements FactoryBean<Car> {

    private String carName;

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    @Override
    public Car getObject() throws Exception {
        if (carName.equals("Bmw")) {
            return new Bmw();
        } else if (carName.equals("Benz")) {
            return new Benz();
        } else {
            return null;
        }
    }

    public void setCarName(String carName) {
        this.carName = carName;
    }
}
<?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-4.1.xsd">
    <bean id="car" class="com.zhuoli.service.spring.explore.factorybean.CarFactoryBean">
        <property name="carName" value="Bmw"/>
    </bean>
</beans>
public class FactoryBeanTest {
    public static void main(String[] args) {
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-factory-bean.xml");
        Car car = (Car) applicationContext.getBean("car");
        car.driving();
    }
}

執行結果:

Bmw driving

當我們把spring-factory-bean.xml配置文件中的value改爲“Benz”時,同樣執行上述代碼,會得到執行結果:

Benz driving

所以通過FactoryBean,最後得到的並不是FactoryBean本身,而是FactoryBean的泛型對象,這就是FactoryBean的作用。FactoryBean的幾個方法:

  • getObject():具體Bean的實例化過程
  • getObjectType():接口返回的實例的Class對象
  • isSingleton():返回該Bean是否爲一個單例的Bean

我們回頭看一下在面試中經常會問到的一個概念,BeanFactory和FactoryBean的關係?答案就非常明確了,這兩者之間其實沒有什麼可比較的關係,只是命名比較接近。BeanFactory是Bean工廠,控制所有Bean的生成,實現了Spring IOC的基本功能。而FactoryBean是一種特殊的Bean,爲IOC容器中的Bean提供了更加靈活的實現方式。

4. BeanPostProcessor

上面介紹的InitializingBean、DisposableBean、FactoryBean包括init-method和destory-method,都是針對某個Bean控制其初始化的操作,而似乎沒有一種辦法可以針對每個Bean的生成前後做一些邏輯操作,BeanPostProcessor可以幫我們做到這一點。BeanPostProcessor接口中定義了兩個方法:

  • postProcessBeforeInitialization:在Bean初始化前調用
  • postProcessAfterInitialization:在Bean初始化後調用

下面看個簡單的示例:

public class TestBean implements InitializingBean, DisposableBean {
    private String testName;

    public void setTestName(String testName) {
        System.out.println("Call TestBean.setName()");
        this.testName = testName;
    }

    public void destroy() throws Exception {
        System.out.println("Call TestBean.destroy(), DisposableBean");
    }


    public void afterPropertiesSet() throws Exception {
        System.out.println("Call TestBean.afterPropertiesSet(), InitializingBean");
    }

    public void initMethod() {
        System.out.println("Call TestBean.initMethod(), init-method");
    }

    public void destroyMethod() {
        System.out.println("Call TestBean.destroyMethod(), destroy-method");
    }
}
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = " + beanName);
        return bean;
    }
}
<?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-4.1.xsd">
    <bean id="testBean0" class="com.zhuoli.service.spring.explore.beanpostprocessor.TestBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="testName" value="testName0"/>
    </bean>
    <bean id="testBean1" class="com.zhuoli.service.spring.explore.beanpostprocessor.TestBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="testName" value="testName1"/>
    </bean>
    <bean id="myBeanPostProcessor" class="com.zhuoli.service.spring.explore.beanpostprocessor.MyBeanPostProcessor" />
</beans>
public class BeanPostProcessorTest {
    public static void main(String[] args) {
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-bean-post-processor.xml");
        applicationContext.close();
    }
}

運行結果:

Call TestBean.setName()
Call TestBean.setBeanName(), BeanNameAware, beanName = testBean0
Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = testBean0
Call TestBean.afterPropertiesSet(), InitializingBean
Call TestBean.initMethod(), init-method
Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = testBean0
Call TestBean.setName()
Call TestBean.setBeanName(), BeanNameAware, beanName = testBean1
Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = testBean1
Call TestBean.afterPropertiesSet(), InitializingBean
Call TestBean.initMethod(), init-method
Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = testBean1
Call TestBean.destroy(), DisposableBean
Call TestBean.destroyMethod(), destroy-method
Call TestBean.destroy(), DisposableBean
Call TestBean.destroyMethod(), destroy-method

可以看到在每個Bean填充屬性(populateBean)之後,調用init-method之前,會執行Aware接口,BeanPostProcessor的postProcessBeforeInitialization方法和InitializingBean的afterPropertiesSet方法,並且優先級順序依次是Aware接口、BeanPostProcessor和InitializingBeanBeanPostProcessor的postProcessAfterInitialization方法會在每個Bean調用init-method之後執行。所以我們大致可以得到下面這個Bean生命週期圖:

另外需要注意的是,postProcessBeforeInitialization和postProcessAfterInitialization這兩個方法是有返回值的,不要返回null,否則getBean的時候拿不到對象

5. BeanFactoryPostProcessor

Spring允許在Bean創建之前,讀取Bean的元屬性,並根據自己的需求對元屬性進行改變,比如將Bean的scope從singleton改變爲prototype,最典型的應用應當是PropertySourcesPlaceholderConfigurer,替換xml文件中的佔位符,替換爲properties文件中相應的key對應的value等。這些工作都可以在BeanFactoryPostProcessor中完成。下面來看示例:

新增一個類MyBeanFactoryPostProcessor,實現BeanFactoryPostProcessor接口。

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("Call TestBean.postProcessBeanFactory(), BeanFactoryPostProcessor");
    }
}

新增一個類MyBeanPostProcessor,實現BeanPostProcessor接口。

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = " + beanName);
        return bean;
    }
}

新增一個測試Bean TestBean

public class TestBean implements BeanNameAware, InitializingBean, DisposableBean {
    private String testName;

    public void setTestName(String testName) {
        System.out.println("Call TestBean.setName()");
        this.testName = testName;
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("Call TestBean.setBeanName(), BeanNameAware, beanName = " + s);
    }

    public void destroy() throws Exception {
        System.out.println("Call TestBean.destroy(), DisposableBean");
    }


    public void afterPropertiesSet() throws Exception {
        System.out.println("Call TestBean.afterPropertiesSet(), InitializingBean");
    }

    public void initMethod() {
        System.out.println("Call TestBean.initMethod(), init-method");
    }

    public void destroyMethod() {
        System.out.println("Call TestBean.destroyMethod(), destroy-method");
    }
}

新增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-4.1.xsd">
    <bean id="testBean0" class="com.zhuoli.service.spring.explore.beanfartorypostprocessor.TestBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="testName" value="testName0"/>
    </bean>
    <bean id="testBean1" class="com.zhuoli.service.spring.explore.beanfartorypostprocessor.TestBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="testName" value="testName1"/>
    </bean>
    <bean id="myBeanPostProcessor" class="com.zhuoli.service.spring.explore.beanfartorypostprocessor.MyBeanPostProcessor" />
    <bean id="myBeanFactoryPostProcessor" class="com.zhuoli.service.spring.explore.beanfartorypostprocessor.MyBeanFactoryPostProcessor" />
</beans>
public class BeanFactoryPostProcessorTest {
    public static void main(String[] args) {
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-bean-factory-post-processor.xml");
        applicationContext.close();
    }
}

運行結果:

Call TestBean.postProcessBeanFactory(), BeanFactoryPostProcessor
Call TestBean.setName()
Call TestBean.setBeanName(), BeanNameAware, beanName = testBean0
Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = testBean0
Call TestBean.afterPropertiesSet(), InitializingBean
Call TestBean.initMethod(), init-method
Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = testBean0
Call TestBean.setName()
Call TestBean.setBeanName(), BeanNameAware, beanName = testBean1
Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = testBean1
Call TestBean.afterPropertiesSet(), InitializingBean
Call TestBean.initMethod(), init-method
Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = testBean1
Call TestBean.destroy(), DisposableBean
Call TestBean.destroyMethod(), destroy-method
Call TestBean.destroy(), DisposableBean
Call TestBean.destroyMethod(), destroy-method

跟上述4介紹BeanPostProcessor唯一不同的地方在於,在調用set方法設置Bean屬性之前,調用了BeanFactoryPostProcessor的postProcessBeanFactory()方法,並且只調用了一次。所以可以看出:

  • BeanFactoryPostProcessor的執行先於BeanPostProcessor
  • BeanFactoryPostProcessor的postProcessBeanFactory()方法只會執行一次

結論也可以解釋,BeanFactoryPostProcessor中定義的方法是在AbstractApplicationContext類中的refresh()方法中調用invokeBeanFactoryPostProcessors()方法實現的,而Bean的初始化是在之後調用finishBeanFactoryInitialization()方法實現的。所以BeanFactoryPostProcessor的執行先於BeanPostProcessor。

同時我們注意到postProcessBeanFactory方法的參數類型是ConfigurableListableBeanFactory,這就是爲什麼可以使用BeanFactoryPostProcessor來改變Bean的屬性相對應起來了。ConfigurableListableBeanFactory功能非常豐富,它攜帶了每個Bean的基本信息。比如我們可以獲取如下信息:

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("Call TestBean.postProcessBeanFactory(), BeanFactoryPostProcessor");
        BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("common0");
        MutablePropertyValues beanProperty = beanDefinition.getPropertyValues();
        System.out.println("scope before change:" + beanDefinition.getScope());
        beanDefinition.setScope("singleton");
        System.out.println("scope after change:" + beanDefinition.getScope());
        System.out.println("beanProperty:" + beanProperty);
    }
}

6. InstantiationAwareBeanPostProcessor

上述介紹的幾個Bean擴展接口都作用於Bean的初始化過程,其實Bean構建還包括一個過程——實例化。而這裏要介紹的擴展接口InstantiationAwareBeanPostProcessor就是作用於這兩個階段,我們首先來看一下實例化和初始化的關係:

  • 實例化:創建Bean的過程,即調用Bean的構造函數構造Bean實例
  • 初始化:在Spring中的初始化可以理解爲在調用Bean的setter方法設置屬性後,調用init-method設置Bean的屬性這一階段

下面看個簡單的示例,來認識一下InstantiationAwareBeanPostProcessor。

public class TestBean implements BeanNameAware, InitializingBean, DisposableBean {
    private String testName;

    public TestBean() {
        System.out.println("Call TestBean's constructor");
    }

    public void setTestName(String testName) {
        System.out.println("Call TestBean.setName()");
        this.testName = testName;
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("Call TestBean.setBeanName(), BeanNameAware, beanName = " + s);
    }

    public void destroy() throws Exception {
        System.out.println("Call TestBean.destroy(), DisposableBean");
    }


    public void afterPropertiesSet() throws Exception {
        System.out.println("Call TestBean.afterPropertiesSet(), InitializingBean");
    }

    public void initMethod() {
        System.out.println("Call TestBean.initMethod(), init-method");
    }

    public void destroyMethod() {
        System.out.println("Call TestBean.destroyMethod(), destroy-method");
    }
}
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = " + beanName);
        return bean;
    }
}
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    public Object postProcessBeforeInstantiation(Class<?> bean, String beanName) throws BeansException {
        System.out.println("Call MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(), InstantiationAwareBeanPostProcessor");
        return null;
    }

    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(), InstantiationAwareBeanPostProcessor");
        return true;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyInstantiationAwareBeanPostProcessor.postProcessBeforeInitialization(), InstantiationAwareBeanPostProcessor");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Call MyInstantiationAwareBeanPostProcessor.postProcessAfterInitialization(), InstantiationAwareBeanPostProcessor");
        return bean;
    }
}
<?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-4.1.xsd">
    <bean id="testBean0" class="com.zhuoli.service.spring.explore.instantiationawarebeanpostprocessor.TestBean" init-method="initMethod" destroy-method="destroyMethod">
        <property name="testName" value="testName"/>
    </bean>
    <bean id="myBeanPostProcessor" class="com.zhuoli.service.spring.explore.beanpostprocessor.MyBeanPostProcessor" />
    <bean id="myInstantiationAwareBeanPostProcessor" class="com.zhuoli.service.spring.explore.instantiationawarebeanpostprocessor.MyInstantiationAwareBeanPostProcessor" />
</beans>
public class InstantiationAwareBeanPostProcessorTest {
    public static void main(String[] args) {
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-instantiation-aware-bean-post-processor.xml");
        applicationContext.close();
    }
}

運行結果:

Call MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(), InstantiationAwareBeanPostProcessor
Call TestBean's constructor
Call MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(), InstantiationAwareBeanPostProcessor
Call TestBean.setName()
Call TestBean.setBeanName(), BeanNameAware, beanName = testBean0
Call MyBeanPostProcessor.postProcessBeforeInitialization(), beanName = testBean0
Call MyInstantiationAwareBeanPostProcessor.postProcessBeforeInitialization(), InstantiationAwareBeanPostProcessor
Call TestBean.afterPropertiesSet(), InitializingBean
Call TestBean.initMethod(), init-method
Call MyBeanPostProcessor.postProcessAfterInitialization(), beanName = testBean0
Call MyInstantiationAwareBeanPostProcessor.postProcessAfterInitialization(), InstantiationAwareBeanPostProcessor
Call TestBean.destroy(), DisposableBean
Call TestBean.destroyMethod(), destroy-method

可以看出以下幾點:

  • postProcessBeforeInstantiation()方法會在調用構造方法實例化前調用
  • postProcessAfterInstantiation()方法會在構造函數方法結束後調用
  • InstantiationAwareBeanPostProcessor從BeanPostProcessor中繼承的方法跟普通的BeanPostProcessor一樣,會在init-method方法前後調用

通常來講,我們不會直接實現InstantiationAwareBeanPostProcessor接口,而是會採用繼承InstantiationAwareBeanPostProcessorAdapter這個抽象類的方式來使用。

加上InstantiationAwareBeanPostProcessor,我們再來看一下Bean的初始化流程:

參考鏈接:

1. Spring源碼

2. 一些常用的Spring Bean擴展接口

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章