Aware接口是針對某個 實作這些接口的Bean 定制初始化的過程,
Spring還可針對容器中 所有Bean 或 某些Bean 定制初始化過程,隻需提供一個實作BeanPostProcessor接口的實作類。
該接口包含如下方法:
-
postProcessBeforeInitialization
在容器中的Bean初始化之前執行
-
postProcessAfterInitialization
在容器中的Bean初始化之後執行
執行個體
public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("執行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("執行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
return bean;
}
}
要将BeanPostProcessor的Bean像其他Bean一樣定義在配置檔案中
<bean class="com.javaedge.spring.service.CustomerBeanPostProcessor"/>
總結
Spring Bean的生命周期
Bean容器找到配置檔案中 Spring Bean 的定義。
Bean容器利用反射建立一個Bean的執行個體。
如果涉及到一些屬性值,利用set方法設定一些屬性值。
如果Bean實作了BeanNameAware接口,調用setBeanName()方法,傳入Bean的名字
如果Bean實作了BeanClassLoaderAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的執行個體
如果Bean實作了BeanFactoryAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的執行個體
與上面的類似,如果實作了其他Aware接口,就調用相應的方法。
如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessBeforeInitialization()方法
若Bean實作InitializingBean接口,執行afterPropertiesSet()
若Bean定義包含init-method屬性,執行指定方法
如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessAfterInitialization()方法
當要銷毀Bean的時候,如果Bean實作了DisposableBean接口,執行destroy()方法。
當要銷毀Bean的時候,如果Bean在配置檔案中的定義包含destroy-method屬性,執行指定的方法。
單例管理的對象
當scope=”singleton”,即預設情況下,會在啟動容器時(即執行個體化容器時)時執行個體化。但我們可以指定Bean節點的lazy-init=”true”來延遲初始化bean,這時候,隻有在第一次擷取bean時才會初始化bean,即第一次請求該bean時才初始化。如下配置:
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>
如果想對所有的預設單例bean都應用延遲初始化,可以在根節點beans設定default-lazy-init屬性為true,如下所示:
<beans default-lazy-init="true" …>
預設情況下,Spring 在讀取 xml 檔案的時候,就會建立對象。在建立對象的時候先調用構造器,然後調用 init-method 屬性值中所指定的方法。對象在被銷毀的時候,會調用 destroy-method 屬性值中所指定的方法(例如調用Container.destroy()方法的時候)。寫一個測試類,代碼如下:
public class LifeBean {
private String name;
public LifeBean(){
System.out.println("LifeBean()構造函數");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName()");
this.name = name;
}
public void init(){
System.out.println("this is init of lifeBean");
}
public void destory(){
System.out.println("this is destory of lifeBean " + this);
}
}
life.xml配置如下:
<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton"
init-method="init" destroy-method="destory" lazy-init="true"/>
測試代碼:
public class LifeTest {
@Test
public void test() {
AbstractApplicationContext container =
new ClassPathXmlApplicationContext("life.xml");
LifeBean life1 = (LifeBean)container.getBean("life");
System.out.println(life1);
container.close();
}
}
結果:
LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@573f2bb1
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1
非單例管理的對象
當scope=”prototype”時,容器也會延遲初始化 bean,Spring 讀取xml 檔案的時候,并不會立刻建立對象,而是在第一次請求該 bean 時才初始化(如調用getBean方法時)。在第一次請求每一個 prototype 的bean 時,Spring容器都會調用其構造器建立這個對象,然後調用init-method屬性值中所指定的方法。對象銷毀的時候,Spring 容器不會幫我們調用任何方法,因為是非單例,這個類型的對象有很多個,Spring容器一旦把這個對象交給你之後,就不再管理這個對象了。
為了測試prototype bean的生命周期,life.xml配置如下:
<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" init-method="init" destroy-method="destory"/>
測試程式:
public class LifeTest {
@Test
public void test() {
AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
LifeBean life1 = (LifeBean)container.getBean("life_singleton");
System.out.println(life1);
LifeBean life3 = (LifeBean)container.getBean("life_prototype");
System.out.println(life3);
container.close();
}
}
運作結果:
LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@573f2bb1
LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@5ae9a829
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1
可以發現,對于作用域為 prototype 的 bean ,其destroy方法并沒有被調用。如果 bean 的 scope 設為prototype時,當容器關閉時,destroy 方法不會被調用。對于 prototype 作用域的 bean,有一點非常重要,那就是 Spring不能對一個 prototype bean 的整個生命周期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype執行個體後,将它交給用戶端,随後就對該prototype執行個體不聞不問了。 不管何種作用域,容器都會調用所有對象的初始化生命周期回調方法。但對prototype而言,任何配置好的析構生命周期回調方法都将不會被調用。清除prototype作用域的對象并釋放任何prototype bean所持有的昂貴資源,都是用戶端代碼的職責(讓Spring容器釋放被prototype作用域bean占用資源的一種可行方式是,通過使用bean的後置處理器,該處理器持有要被清除的bean的引用)。談及prototype作用域的bean時,在某些方面你可以将Spring容器的角色看作是Java new操作的替代者,任何遲于該時間點的生命周期事宜都得交由用戶端來處理。
Spring 容器可以管理 singleton 作用域下 bean 的生命周期,在此作用域下,Spring 能夠精确地知道bean何時被建立,何時初始化完成,以及何時被銷毀。而對于 prototype 作用域的bean,Spring隻負責建立,當容器建立了 bean 的執行個體後,bean 的執行個體就交給了用戶端的代碼管理,Spring容器将不再跟蹤其生命周期,并且不會管理那些被配置成prototype作用域的bean的生命周期。