前言
在 Spring 中翠订,那些組成應(yīng)用程序的主體及由 Spring IOC 容器所管理的對(duì)象婚夫,被稱之為 bean。簡(jiǎn)單地講程帕,bean 就是由 IOC 容器初始化、裝配及管理的對(duì)象地啰,除此之外愁拭,bean 就與應(yīng)用程序中的其他對(duì)象沒有什么區(qū)別了。而 bean 的定義以及 bean 相互間的依賴關(guān)系將通過配置元數(shù)據(jù)來描述亏吝。
Spring中的bean默認(rèn)都是單例的岭埠,這些單例Bean在多線程程序下如何保證線程安全呢? 例如對(duì)于Web應(yīng)用來說,Web容器對(duì)于每個(gè)用戶請(qǐng)求都創(chuàng)建一個(gè)單獨(dú)的Sevlet線程來處理請(qǐng)求趁舀,引入Spring框架之后坎炼,每個(gè)Action都是單例的扒袖,那么對(duì)于Spring托管的單例Service Bean,如何保證其安全呢混聊? Spring的單例是基于BeanFactory也就是Spring容器的,單例Bean在此容器內(nèi)只有一個(gè)乾巧,Java的單例是基于 JVM句喜,每個(gè) JVM 內(nèi)只有一個(gè)實(shí)例。
bean的作用域
創(chuàng)建一個(gè)bean定義沟于,其實(shí)質(zhì)是用該bean定義對(duì)應(yīng)的類來創(chuàng)建真正實(shí)例的“配方”咳胃。把bean定義看成一個(gè)配方很有意義,它與class很類似旷太,只根據(jù)一張“處方”就可以創(chuàng)建多個(gè)實(shí)例展懈。不僅可以控制注入到對(duì)象中的各種依賴和配置值,還可以控制該對(duì)象的作用域泳秀。這樣可以靈活選擇所建對(duì)象的作用域标沪,而不必在Java Class級(jí)定義作用域。Spring Framework支持五種作用域嗜傅,分別闡述如下表金句。
類別 | 說明 |
---|---|
singleton | 在Spring IoC容器中僅存在一個(gè)Bean實(shí)例,Bean以單例方式存在吕嘀,默認(rèn)值 |
prototype | 每次從容器中調(diào)用Bean時(shí)违寞,都返回一個(gè)新的實(shí)例,即每次調(diào)用getBean()時(shí)偶房,相當(dāng)于執(zhí)行new XxxBean() |
request | 每次HTTP請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的Bean趁曼,該該作用域僅適用于WebApplicationContext環(huán)境 |
session | 同一個(gè)HTTP Session共享一個(gè)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 實(shí)例愧捕,當(dāng)一個(gè) bean 的作用域?yàn)?singleton奢驯,那么Spring IoC容器中只會(huì)存在一個(gè)共享的 bean 實(shí)例,并且所有對(duì) bean 的請(qǐng)求次绘,只要 id 與該 bean 定義相匹配瘪阁,則只會(huì)返回bean的同一實(shí)例撒遣。 singleton 是單例類型(對(duì)應(yīng)于單例模式),就是在創(chuàng)建起容器時(shí)就同時(shí)自動(dòng)創(chuàng)建了一個(gè)bean的對(duì)象管跺,不管你是否使用义黎,但我們可以指定Bean節(jié)點(diǎn)的 lazy-init=”true” 來延遲初始化bean,這時(shí)候伙菜,只有在第一次獲取bean時(shí)才會(huì)初始化bean轩缤,即第一次請(qǐng)求該bean時(shí)才初始化。 每次獲取到的對(duì)象都是同一個(gè)對(duì)象贩绕。注意火的,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每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的 bean 實(shí)例,當(dāng)一個(gè)bean的作用域?yàn)?prototype,表示一個(gè) bean 定義對(duì)應(yīng)多個(gè)對(duì)象實(shí)例娇哆。prototype 作用域的 bean 會(huì)導(dǎo)致在每次對(duì)該 bean 請(qǐng)求(將其注入到另一個(gè) bean 中湃累,或者以程序的方式調(diào)用容器的 getBean() 方法)時(shí)都會(huì)創(chuàng)建一個(gè)新的 bean 實(shí)例。prototype 是原型類型碍讨,它在我們創(chuàng)建容器的時(shí)候并沒有實(shí)例化治力,而是當(dāng)我們獲取bean的時(shí)候才會(huì)去創(chuàng)建一個(gè)對(duì)象,而且我們每次獲取到的對(duì)象都不是同一個(gè)對(duì)象勃黍。根據(jù)經(jīng)驗(yàn)宵统,對(duì)有狀態(tài)的 bean 應(yīng)該使用 prototype 作用域,而對(duì)無狀態(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 注解的方式實(shí)現(xiàn)就不做演示了。
request
request每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean弄息,該bean僅在當(dāng)前HTTP request內(nèi)有效,request只適用于Web程序痊班,每一次 HTTP 請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,同時(shí)該bean僅在當(dāng)前HTTP request內(nèi)有效摹量,當(dāng)請(qǐng)求結(jié)束后涤伐,該對(duì)象的生命周期即告結(jié)束。 在 XML 中將 bean 定義成 request 缨称,可以這樣配置:
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
session
session每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的 bean废亭,該bean僅在當(dāng)前 HTTP session 內(nèi)有效,session只適用于Web程序,session 作用域表示該針對(duì)每一次 HTTP 請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的 bean具钥,同時(shí)該 bean 僅在當(dāng)前 HTTP session 內(nèi)有效.與request作用域一樣,可以根據(jù)需要放心的更改所創(chuàng)建實(shí)例的內(nèi)部狀態(tài)液兽,而別的 HTTP session 中根據(jù) userPreferences 創(chuàng)建的實(shí)例骂删,將不會(huì)看到這些特定于某個(gè) HTTP session 的狀態(tài)變化掌动。當(dāng)HTTP session最終被廢棄的時(shí)候,在該HTTP session作用域內(nèi)的bean也會(huì)被廢棄掉宁玫。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
globalSession
global session 作用域類似于標(biāo)準(zhǔn)的 HTTP session 作用域粗恢,不過僅僅在基于 portlet 的 web 應(yīng)用中才有意義。Portlet 規(guī)范定義了全局 Session 的概念欧瘪,它被所有構(gòu)成某個(gè) 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 何時(shí)被創(chuàng)建,何時(shí)初始化完成芥被,以及何時(shí)被銷毀欧宜。
而對(duì)于 prototype 作用域的 Bean,Spring 只負(fù)責(zé)創(chuàng)建拴魄,當(dāng)容器創(chuàng)建了 Bean 的實(shí)例后冗茸,Bean 的實(shí)例就交給客戶端代碼管理,Spring 容器將不再跟蹤其生命周期匹中。每次客戶端請(qǐng)求 prototype 作用域的 Bean 時(shí)夏漱,Spring 容器都會(huì)創(chuàng)建一個(gè)新的實(shí)例,并且不會(huì)管那些被配置成 prototype 作用域的 Bean 的生命周期顶捷。
了解 Spring 生命周期的意義就在于挂绰,可以利用 Bean 在其存活期間的指定時(shí)刻完成一些相關(guān)操作。這種時(shí)刻可能有很多焊切,但一般情況下扮授,會(huì)在 Bean 被初始化后和被銷毀前執(zhí)行一些相關(guān)操作。
在 Spring 中专肪,Bean 的生命周期是一個(gè)很復(fù)雜的執(zhí)行過程刹勃,我們可以利用 Spring 提供的方法定制 Bean 的創(chuàng)建過程。
當(dāng)一個(gè) Bean 被加載到 Spring 容器時(shí)嚎尤,它就具有了生命荔仁,而 Spring 容器在保證一個(gè) Bean 能夠使用之前,會(huì)進(jìn)行很多工作芽死。Spring 容器中 Bean 的生命周期流程如圖 1 所示乏梁。
Bean 生命周期的整個(gè)執(zhí)行過程描述如下:
1、根據(jù)配置情況調(diào)用 Bean 構(gòu)造方法或工廠方法實(shí)例化 Bean关贵。
2遇骑、利用依賴注入完成 Bean 中所有屬性值的配置注入。
3揖曾、如果 Bean 實(shí)現(xiàn)了 BeanNameAware 接口落萎,則 Spring 調(diào)用 Bean 的 setBeanName() 方法傳入當(dāng)前 Bean 的 id 值亥啦。
4、如果 Bean 實(shí)現(xiàn)了 BeanFactoryAware 接口练链,則 Spring 調(diào)用 setBeanFactory() 方法傳入當(dāng)前工廠實(shí)例的引用翔脱。
5、如果 Bean 實(shí)現(xiàn)了 ApplicationContextAware 接口媒鼓,則 Spring 調(diào)用 setApplicationContext() 方法傳入當(dāng)前 ApplicationContext 實(shí)例的引用届吁。
6、如果 BeanPostProcessor 和 Bean 關(guān)聯(lián)绿鸣,則 Spring 將調(diào)用該接口的預(yù)初始化方法 postProcessBeforeInitialzation() 對(duì) Bean 進(jìn)行加工操作疚沐,此處非常重要,Spring 的 AOP 就是利用它實(shí)現(xiàn)的枚驻。
7濒旦、如果 Bean 實(shí)現(xiàn)了 InitializingBean 接口,則 Spring 將調(diào)用 afterPropertiesSet() 方法再登。
8尔邓、如果在配置文件中通過 init-method 屬性指定了初始化方法,則調(diào)用該初始化方法锉矢。
9梯嗽、如果 BeanPostProcessor 和 Bean 關(guān)聯(lián),則 Spring 將調(diào)用該接口的初始化方法 postProcessAfterInitialization()沽损。此時(shí)灯节,Bean 已經(jīng)可以被應(yīng)用系統(tǒng)使用了。
10绵估、如果在 <bean> 中指定了該 Bean 的作用范圍為 scope="singleton"炎疆,則將該 Bean 放入 Spring IoC 的緩存池中,將觸發(fā) Spring 對(duì)該 Bean 的生命周期管理国裳;如果在 <bean> 中指定了該 Bean 的作用范圍為 scope="prototype"形入,則將該 Bean 交給調(diào)用者,調(diào)用者管理該 Bean 的生命周期缝左,Spring 不再管理該 Bean亿遂。
11、如果 Bean 實(shí)現(xiàn)了 DisposableBean 接口渺杉,則 Spring 會(huì)調(diào)用 destory() 方法將 Spring 中的 Bean 銷毀蛇数;如果在配置文件中通過 destory-method 屬性指定了 Bean 的銷毀方法,則 Spring 將調(diào)用該方法對(duì) Bean 進(jìn)行銷毀是越。
Spring 為 Bean 提供了細(xì)致全面的生命周期過程耳舅,通過實(shí)現(xiàn)特定的接口或 <bean> 的屬性設(shè)置,都可以對(duì) Bean 的生命周期過程產(chǎn)生影響倚评。雖然可以隨意配置 <bean> 的屬性挽放,但是建議不要過多地使用 Bean 實(shí)現(xiàn)接口绍赛,因?yàn)檫@樣會(huì)導(dǎo)致代碼和 Spring 的聚合過于緊密。
BeanPostProcessor
該接口我們也叫后置處理器辑畦,作用是在Bean對(duì)象在實(shí)例化和依賴注入完畢后,在顯示調(diào)用初始化方法的前后添加我們自己的邏輯腿倚。注意是Bean實(shí)例化完畢后及依賴注入完成后觸發(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 | 實(shí)例化、依賴注入完畢敷燎,在調(diào)用顯示的初始化之前完成 一些定制的初始化任務(wù) |
postProcessAfterInitialization | 實(shí)例化暂筝、依賴注入、初始化完畢時(shí)執(zhí)行 |
一硬贯、自定義后置處理器演示
1焕襟、自定義處理器
package com.dpb.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 自定義BeanPostProcessor實(shí)現(xiàn)類
* BeanPostProcessor接口的作用是:
* 我們可以通過該接口中的方法在bean實(shí)例化、配置以及其他初始化方法前后添加一些我們自己的邏輯
* @author dengp
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* 實(shí)例化饭豹、依賴注入完畢鸵赖,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
/**
* 實(shí)例化拄衰、依賴注入它褪、初始化完畢時(shí)執(zhí)行
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
}
注意:接口中兩個(gè)方法不能返回null翘悉,如果返回null那么在后續(xù)初始化方法將報(bào)空指針異趁4颍或者通過getBean()方法獲取不到bena實(shí)例對(duì)象,因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中妖混。
2老赤、Pojo類
public class User {
private int id;
private String name;
private String beanName;
public User(){
System.out.println("User 被實(shí)例化");
}
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、配置文件注冊(cè)
<?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>
<!-- 注冊(cè)處理器 -->
<bean class="com.dpb.processor.MyBeanPostProcessor"></bean>
</beans>
4制市、測(cè)試
@Test
public void test() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = ac.getBean(User.class);
System.out.println(user);
}
輸出結(jié)果:
User 被實(shí)例化
設(shè)置:波波烤鴨
before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@65e2dbf3 user
User 中自定義的初始化方法
after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@65e2dbf3 user
com.dpb.pojo.User@65e2dbf3
通過輸出語句我們也能看到postProcessBeforeInitialization方法的輸出語句是在Bean實(shí)例化及屬性注入后執(zhí)行的抬旺,且在自定義的初始化方法之前執(zhí)行(通過init-method指定)。而postProcessAfterInitialization方法是在自定義初始化方法執(zhí)行之后執(zhí)行的息堂。
注意:
- BeanFactory和ApplicationContext兩個(gè)容器對(duì)待bean的后置處理器稍微有些不同嚷狞。ApplicationContext容器會(huì)自動(dòng)檢測(cè)Spring配置文件中那些bean所對(duì)應(yīng)的Java類實(shí)現(xiàn)了BeanPostProcessor接口,并自動(dòng)把它們注冊(cè)為后置處理器荣堰。在創(chuàng)建bean過程中調(diào)用它們床未,所以部署一個(gè)后置處理器跟普通的bean沒有什么太大區(qū)別。
- BeanFactory容器注冊(cè)bean后置處理器時(shí)必須通過代碼顯示的注冊(cè)振坚,在IoC容器繼承體系中的ConfigurableBeanFactory接口中定義了注冊(cè)方法
/**
* 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);
測(cè)試代碼如下
@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);
}
二薇搁、多個(gè)后置處理器
我們可以在Spring配置文件中添加多個(gè)BeanPostProcessor(后置處理器)接口實(shí)現(xiàn)類,在默認(rèn)情況下Spring容器會(huì)根據(jù)后置處理器的定義順序來依次調(diào)用渡八。
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* 實(shí)例化啃洋、依賴注入完畢传货,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("A before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
/**
* 實(shí)例化宏娄、依賴注入问裕、初始化完畢時(shí)執(zhí)行
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("A after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
}
public class MyBeanPostProcessor2 implements BeanPostProcessor{
/**
* 實(shí)例化孵坚、依賴注入完畢粮宛,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("B before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
/**
* 實(shí)例化卖宠、依賴注入巍杈、初始化完畢時(shí)執(zhí)行
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("B after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
}
配置文件注冊(cè)
<?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>
<!-- 注冊(cè)處理器 -->
<bean class="com.dpb.processor.MyBeanPostProcessor"/>
<bean class="com.dpb.processor.MyBeanPostProcessor2"/>
</beans>
測(cè)試結(jié)果:
User 被實(shí)例化
設(shè)置:波波烤鴨
A before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
B before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
User 中自定義的初始化方法
A after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
B after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b
三扛伍、顯示指定順序
在Spring機(jī)制中可以指定后置處理器調(diào)用順序筷畦,通過讓BeanPostProcessor接口實(shí)現(xiàn)類實(shí)現(xiàn)Ordered接口getOrder方法,該方法返回一整數(shù)刺洒,默認(rèn)值為 0鳖宾,優(yōu)先級(jí)最高,值越大優(yōu)先級(jí)越低
public class MyBeanPostProcessor implements BeanPostProcessor,Ordered{
/**
* 實(shí)例化作媚、依賴注入完畢攘滩,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("A before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
/**
* 實(shí)例化纸泡、依賴注入漂问、初始化完畢時(shí)執(zhí)行
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("A after...實(shí)例化的bean對(duì)象:"+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{
/**
* 實(shí)例化女揭、依賴注入完畢蚤假,在調(diào)用顯示的初始化之前完成一些定制的初始化任務(wù)
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("B before--實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
/**
* 實(shí)例化吧兔、依賴注入磷仰、初始化完畢時(shí)執(zhí)行
* 注意:方法返回值不能為null
* 如果返回null那么在后續(xù)初始化方法將報(bào)空指針異常或者通過getBean()方法獲取不到bena實(shí)例對(duì)象
* 因?yàn)楹笾锰幚砥鲝腟pring IoC容器中取出bean實(shí)例對(duì)象沒有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("B after...實(shí)例化的bean對(duì)象:"+bean+"\t"+beanName);
// 可以根據(jù)beanName不同執(zhí)行不同的處理操作
return bean;
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 2;
}
}
測(cè)試輸出結(jié)果:
User 被實(shí)例化
設(shè)置:波波烤鴨
B before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
A before--實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
User 中自定義的初始化方法
B after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
A after...實(shí)例化的bean對(duì)象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b
數(shù)值越大的優(yōu)先級(jí)越低境蔼,所以A的輸出就在后面了灶平。
參考:
http://c.biancheng.net/view/4261.html
https://www.cnblogs.com/dengpengbo/p/10464892.html