Spring Bean的生命周期

前言

在 Spring 中,那些組成應(yīng)用程序的主體及由 Spring IOC 容器所管理的對象,被稱之為 bean。簡單地講,bean 就是由 IOC 容器初始化、裝配及管理的對象,除此之外,bean 就與應(yīng)用程序中的其他對象沒有什么區(qū)別了。而 bean 的定義以及 bean 相互間的依賴關(guān)系將通過配置元數(shù)據(jù)來描述。

Spring中的bean默認都是單例的,這些單例Bean在多線程程序下如何保證線程安全呢? 例如對于Web應(yīng)用來說,Web容器對于每個用戶請求都創(chuàng)建一個單獨的Sevlet線程來處理請求,引入Spring框架之后,每個Action都是單例的,那么對于Spring托管的單例Service Bean,如何保證其安全呢? Spring的單例是基于BeanFactory也就是Spring容器的,單例Bean在此容器內(nèi)只有一個,Java的單例是基于 JVM,每個 JVM 內(nèi)只有一個實例。

bean的作用域

創(chuàng)建一個bean定義,其實質(zhì)是用該bean定義對應(yīng)的類來創(chuàng)建真正實例的“配方”。把bean定義看成一個配方很有意義,它與class很類似,只根據(jù)一張“處方”就可以創(chuàng)建多個實例。不僅可以控制注入到對象中的各種依賴和配置值,還可以控制該對象的作用域。這樣可以靈活選擇所建對象的作用域,而不必在Java Class級定義作用域。Spring Framework支持五種作用域,分別闡述如下表。

類別 說明
singleton 在Spring IoC容器中僅存在一個Bean實例,Bean以單例方式存在,默認值
prototype 每次從容器中調(diào)用Bean時,都返回一個新的實例,即每次調(diào)用getBean()時,相當于執(zhí)行new XxxBean()
request 每次HTTP請求都會創(chuàng)建一個新的Bean,該該作用域僅適用于WebApplicationContext環(huán)境
session 同一個HTTP Session共享一個Bean,不同Session使用不同Bean,僅適用于WebApplicationContext環(huán)境
globalSession 一般用于Portlet應(yīng)用環(huán)境,該作用域僅適用于WebApplicationContext環(huán)境

五種作用域中,request、session 和 global session 三種作用域僅在基于web的應(yīng)用中使用(不必關(guān)心你所采用的是什么web應(yīng)用框架),只能用在基于 web 的 Spring ApplicationContext 環(huán)境。

singleton

singleton唯一 bean 實例,當一個 bean 的作用域為 singleton,那么Spring IoC容器中只會存在一個共享的 bean 實例,并且所有對 bean 的請求,只要 id 與該 bean 定義相匹配,則只會返回bean的同一實例。 singleton 是單例類型(對應(yīng)于單例模式),就是在創(chuàng)建起容器時就同時自動創(chuàng)建了一個bean的對象,不管你是否使用,但我們可以指定Bean節(jié)點的 lazy-init=”true” 來延遲初始化bean,這時候,只有在第一次獲取bean時才會初始化bean,即第一次請求該bean時才初始化。 每次獲取到的對象都是同一個對象。注意,singleton 作用域是Spring中的缺省作用域。要在XML中將 bean 定義成 singleton ,可以這樣配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

也可以通過 @Scope 注解(它可以顯示指定bean的作用范圍。)的方式

@Service
@Scope("singleton")
public class ServiceImpl{

}

prototype

prototype每次請求都會創(chuàng)建一個新的 bean 實例,當一個bean的作用域為 prototype,表示一個 bean 定義對應(yīng)多個對象實例。prototype 作用域的 bean 會導(dǎo)致在每次對該 bean 請求(將其注入到另一個 bean 中,或者以程序的方式調(diào)用容器的 getBean() 方法)時都會創(chuàng)建一個新的 bean 實例。prototype 是原型類型,它在我們創(chuàng)建容器的時候并沒有實例化,而是當我們獲取bean的時候才會去創(chuàng)建一個對象,而且我們每次獲取到的對象都不是同一個對象。根據(jù)經(jīng)驗,對有狀態(tài)的 bean 應(yīng)該使用 prototype 作用域,而對無狀態(tài)的 bean 則應(yīng)該使用 singleton 作用域。 在 XML 中將 bean 定義成 prototype ,可以這樣配置:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
 或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 

通過 @Scope 注解的方式實現(xiàn)就不做演示了。

request

request每一次HTTP請求都會產(chǎn)生一個新的bean,該bean僅在當前HTTP request內(nèi)有效,request只適用于Web程序,每一次 HTTP 請求都會產(chǎn)生一個新的bean,同時該bean僅在當前HTTP request內(nèi)有效,當請求結(jié)束后,該對象的生命周期即告結(jié)束。 在 XML 中將 bean 定義成 request ,可以這樣配置:

<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

session

session每一次HTTP請求都會產(chǎn)生一個新的 bean,該bean僅在當前 HTTP session 內(nèi)有效,session只適用于Web程序,session 作用域表示該針對每一次 HTTP 請求都會產(chǎn)生一個新的 bean,同時該 bean 僅在當前 HTTP session 內(nèi)有效.與request作用域一樣,可以根據(jù)需要放心的更改所創(chuàng)建實例的內(nèi)部狀態(tài),而別的 HTTP session 中根據(jù) userPreferences 創(chuàng)建的實例,將不會看到這些特定于某個 HTTP session 的狀態(tài)變化。當HTTP session最終被廢棄的時候,在該HTTP session作用域內(nèi)的bean也會被廢棄掉。

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

globalSession

global session 作用域類似于標準的 HTTP session 作用域,不過僅僅在基于 portlet 的 web 應(yīng)用中才有意義。Portlet 規(guī)范定義了全局 Session 的概念,它被所有構(gòu)成某個 portlet web 應(yīng)用的各種不同的 portle t所共享。在global session 作用域中定義的 bean 被限定于全局portlet Session的生命周期范圍內(nèi)。

<bean id="user" class="com.foo.Preferences "scope="globalSession"/>

Spring Bean的生命周期

Spring容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能夠精確地知道該 Bean 何時被創(chuàng)建,何時初始化完成,以及何時被銷毀。

而對于 prototype 作用域的 Bean,Spring 只負責創(chuàng)建,當容器創(chuàng)建了 Bean 的實例后,Bean 的實例就交給客戶端代碼管理,Spring 容器將不再跟蹤其生命周期。每次客戶端請求 prototype 作用域的 Bean 時,Spring 容器都會創(chuàng)建一個新的實例,并且不會管那些被配置成 prototype 作用域的 Bean 的生命周期。

了解 Spring 生命周期的意義就在于,可以利用 Bean 在其存活期間的指定時刻完成一些相關(guān)操作。這種時刻可能有很多,但一般情況下,會在 Bean 被初始化后和被銷毀前執(zhí)行一些相關(guān)操作。

在 Spring 中,Bean 的生命周期是一個很復(fù)雜的執(zhí)行過程,我們可以利用 Spring 提供的方法定制 Bean 的創(chuàng)建過程。

當一個 Bean 被加載到 Spring 容器時,它就具有了生命,而 Spring 容器在保證一個 Bean 能夠使用之前,會進行很多工作。Spring 容器中 Bean 的生命周期流程如圖 1 所示。

Spring Bean的生命周期
Spring Bean的生命周期

Bean 生命周期的整個執(zhí)行過程描述如下:

  • 1、根據(jù)配置情況調(diào)用 Bean 構(gòu)造方法或工廠方法實例化 Bean。

  • 2、利用依賴注入完成 Bean 中所有屬性值的配置注入。

  • 3、如果 Bean 實現(xiàn)了 BeanNameAware 接口,則 Spring 調(diào)用 Bean 的 setBeanName() 方法傳入當前 Bean 的 id 值。

  • 4、如果 Bean 實現(xiàn)了 BeanFactoryAware 接口,則 Spring 調(diào)用 setBeanFactory() 方法傳入當前工廠實例的引用。

  • 5、如果 Bean 實現(xiàn)了 ApplicationContextAware 接口,則 Spring 調(diào)用 setApplicationContext() 方法傳入當前 ApplicationContext 實例的引用。

  • 6、如果 BeanPostProcessor 和 Bean 關(guān)聯(lián),則 Spring 將調(diào)用該接口的預(yù)初始化方法 postProcessBeforeInitialzation() 對 Bean 進行加工操作,此處非常重要,Spring 的 AOP 就是利用它實現(xiàn)的。

  • 7、如果 Bean 實現(xiàn)了 InitializingBean 接口,則 Spring 將調(diào)用 afterPropertiesSet() 方法。

  • 8、如果在配置文件中通過 init-method 屬性指定了初始化方法,則調(diào)用該初始化方法。

  • 9、如果 BeanPostProcessor 和 Bean 關(guān)聯(lián),則 Spring 將調(diào)用該接口的初始化方法 postProcessAfterInitialization()。此時,Bean 已經(jīng)可以被應(yīng)用系統(tǒng)使用了。

  • 10、如果在 <bean> 中指定了該 Bean 的作用范圍為 scope="singleton",則將該 Bean 放入 Spring IoC 的緩存池中,將觸發(fā) Spring 對該 Bean 的生命周期管理;如果在 <bean> 中指定了該 Bean 的作用范圍為 scope="prototype",則將該 Bean 交給調(diào)用者,調(diào)用者管理該 Bean 的生命周期,Spring 不再管理該 Bean。

  • 11、如果 Bean 實現(xiàn)了 DisposableBean 接口,則 Spring 會調(diào)用 destory() 方法將 Spring 中的 Bean 銷毀;如果在配置文件中通過 destory-method 屬性指定了 Bean 的銷毀方法,則 Spring 將調(diào)用該方法對 Bean 進行銷毀。

Spring 為 Bean 提供了細致全面的生命周期過程,通過實現(xiàn)特定的接口或 <bean> 的屬性設(shè)置,都可以對 Bean 的生命周期過程產(chǎn)生影響。雖然可以隨意配置 <bean> 的屬性,但是建議不要過多地使用 Bean 實現(xiàn)接口,因為這樣會導(dǎo)致代碼和 Spring 的聚合過于緊密。

BeanPostProcessor

該接口我們也叫后置處理器,作用是在Bean對象在實例化和依賴注入完畢后,在顯示調(diào)用初始化方法的前后添加我們自己的邏輯。注意是Bean實例化完畢后及依賴注入完成后觸發(fā)的。接口的源碼如下:

public interface BeanPostProcessor {

    /**
     * Apply this 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.
     * @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
     */
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    /**
     * Apply this 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 BeanPostProcessor callbacks.
     * @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
     */
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}
方法 說明
postProcessBeforeInitialization 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成
一些定制的初始化任務(wù)
postProcessAfterInitialization 實例化、依賴注入、初始化完畢時執(zhí)行

一、自定義后置處理器演示

1、自定義處理器

package com.dpb.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
 * 自定義BeanPostProcessor實現(xiàn)類
 * BeanPostProcessor接口的作用是:
 *   我們可以通過該接口中的方法在bean實例化、配置以及其他初始化方法前后添加一些我們自己的邏輯
 * @author dengp
 *
 */
public class MyBeanPostProcessor implements BeanPostProcessor{

    /**
     * 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("before--實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    /**
     * 實例化、依賴注入、初始化完畢時執(zhí)行 
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異常或者通過getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("after...實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

}

注意:接口中兩個方法不能返回null,如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象,因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中。

2、Pojo類

public class User {

    private int id;
    
    private String name;
    
    private String beanName;
    
    public User(){
        System.out.println("User 被實例化");
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("設(shè)置:"+name);
        this.name = name;
    }

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
    /**
     * 自定義的初始化方法
     */
    public void start(){
        System.out.println("User 中自定義的初始化方法");
    }
}

3、配置文件注冊

<?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 class="com.dpb.pojo.User" id="user" init-method="start">
        <property name="name" value="波波烤鴨" />
    </bean>
    
    <!-- 注冊處理器 -->
    <bean class="com.dpb.processor.MyBeanPostProcessor"></bean>
</beans>

4、測試

@Test
public void test() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = ac.getBean(User.class);
    System.out.println(user);
}

輸出結(jié)果:

User 被實例化
設(shè)置:波波烤鴨
before--實例化的bean對象:com.dpb.pojo.User@65e2dbf3   user
User 中自定義的初始化方法
after...實例化的bean對象:com.dpb.pojo.User@65e2dbf3   user
com.dpb.pojo.User@65e2dbf3

通過輸出語句我們也能看到postProcessBeforeInitialization方法的輸出語句是在Bean實例化及屬性注入后執(zhí)行的,且在自定義的初始化方法之前執(zhí)行(通過init-method指定)。而postProcessAfterInitialization方法是在自定義初始化方法執(zhí)行之后執(zhí)行的。

注意:

  • BeanFactory和ApplicationContext兩個容器對待bean的后置處理器稍微有些不同。ApplicationContext容器會自動檢測Spring配置文件中那些bean所對應(yīng)的Java類實現(xiàn)了BeanPostProcessor接口,并自動把它們注冊為后置處理器。在創(chuàng)建bean過程中調(diào)用它們,所以部署一個后置處理器跟普通的bean沒有什么太大區(qū)別。
  • BeanFactory容器注冊bean后置處理器時必須通過代碼顯示的注冊,在IoC容器繼承體系中的ConfigurableBeanFactory接口中定義了注冊方法
/**
 * Add a new BeanPostProcessor that will get applied to beans created
 * by this factory. To be invoked during factory configuration.
 * <p>Note: Post-processors submitted here will be applied in the order of
 * registration; any ordering semantics expressed through implementing the
 * {@link org.springframework.core.Ordered} interface will be ignored. Note
 * that autodetected post-processors (e.g. as beans in an ApplicationContext)
 * will always be applied after programmatically registered ones.
 * @param beanPostProcessor the post-processor to register
 */
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

測試代碼如下

@Test
public void test2() {
    //ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    // 顯示添加后置處理器
    bf.addBeanPostProcessor(bf.getBean(MyBeanPostProcessor.class));
    User user = bf.getBean(User.class);
    System.out.println(user);
}

二、多個后置處理器

我們可以在Spring配置文件中添加多個BeanPostProcessor(后置處理器)接口實現(xiàn)類,在默認情況下Spring容器會根據(jù)后置處理器的定義順序來依次調(diào)用。

public class MyBeanPostProcessor implements BeanPostProcessor{

    /**
     * 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("A before--實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    /**
     * 實例化、依賴注入、初始化完畢時執(zhí)行 
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異常或者通過getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("A after...實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }
}
public class MyBeanPostProcessor2 implements BeanPostProcessor{

    /**
     * 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("B before--實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    /**
     * 實例化、依賴注入、初始化完畢時執(zhí)行 
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異常或者通過getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("B after...實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        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.xsd">

    <bean class="com.dpb.pojo.User" id="user" init-method="start">
        <property name="name" value="波波烤鴨" />
    </bean>
    
    <!-- 注冊處理器 -->
    <bean class="com.dpb.processor.MyBeanPostProcessor"/>
    <bean class="com.dpb.processor.MyBeanPostProcessor2"/>
</beans>

測試結(jié)果:

User 被實例化
設(shè)置:波波烤鴨
A before--實例化的bean對象:com.dpb.pojo.User@7fac631b user
B before--實例化的bean對象:com.dpb.pojo.User@7fac631b user
User 中自定義的初始化方法
A after...實例化的bean對象:com.dpb.pojo.User@7fac631b user
B after...實例化的bean對象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b

三、顯示指定順序

在Spring機制中可以指定后置處理器調(diào)用順序,通過讓BeanPostProcessor接口實現(xiàn)類實現(xiàn)Ordered接口getOrder方法,該方法返回一整數(shù),默認值為 0,優(yōu)先級最高,值越大優(yōu)先級越低

public class MyBeanPostProcessor implements BeanPostProcessor,Ordered{

    /**
     * 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("A before--實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    /**
     * 實例化、依賴注入、初始化完畢時執(zhí)行 
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異常或者通過getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("A after...實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return 10;
    }
}
public class MyBeanPostProcessor2 implements BeanPostProcessor,Ordered{

    /**
     * 實例化、依賴注入完畢,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("B before--實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    /**
     * 實例化、依賴注入、初始化完畢時執(zhí)行 
     * 注意:方法返回值不能為null
     * 如果返回null那么在后續(xù)初始化方法將報空指針異?;蛘咄ㄟ^getBean()方法獲取不到bena實例對象
     * 因為后置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("B after...實例化的bean對象:"+bean+"\t"+beanName);
        // 可以根據(jù)beanName不同執(zhí)行不同的處理操作
        return bean;
    }

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return 2;
    }
}

測試輸出結(jié)果:

User 被實例化
設(shè)置:波波烤鴨
B before--實例化的bean對象:com.dpb.pojo.User@7fac631b user
A before--實例化的bean對象:com.dpb.pojo.User@7fac631b user
User 中自定義的初始化方法
B after...實例化的bean對象:com.dpb.pojo.User@7fac631b user
A after...實例化的bean對象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b

數(shù)值越大的優(yōu)先級越低,所以A的輸出就在后面了。

參考:
http://c.biancheng.net/view/4261.html

https://www.cnblogs.com/dengpengbo/p/10464892.html

https://www.cnblogs.com/yoci/p/10642553.html

https://my.oschina.net/u/3905482/blog/1859227

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

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