spring心得3--bean的生命週期結合案例詳細講解@普通期圖解與uml圖解一併分析

y_keven發表於2013-04-24

1.繼上一篇部落格續將,bean生命週期理論概括

 bean被載入到容器中時,他的生命週期就開始了。bean工廠在一個bean可以使用前完成很多工作:

1).容器尋找bean的定義資訊並例項化。

2).使用依賴注入,spring按bean定義資訊配置bean的所有屬性。

3).若bean實現了BeanNameAware介面,工廠呼叫Bean的setBeanName()方法傳遞bean的ID。

4).若bean實現了BeanFactoryAware介面,工廠呼叫setBeanFactory()方法傳入工廠自身。

5).若BeanPostProcessor和bean關聯,則它們的 postProcessBeforeInitialization()方法被呼叫。

6).若bean指定了ini-method方法、,它將被呼叫。

7).最後,若有BeanPostProcessor和bean關聯,則它們的postProcessAfterInitialization()方法被呼叫。

    將bean從工廠中刪掉有兩種方法:

1).若bean實現了DisposableBean介面,distroy()方法被呼叫。

2).如果指定了定製的銷燬方法,就呼叫這個方法。

bean在應用上下文中的生命週期和在bean工廠的生命週期唯一不同的是:若bean實現了ApplicationContextAware()介面,setApplicationContext()方法會被呼叫。

2.案例加註釋詳細剖解bean的生命週期

  測試類的程式碼

package www.csdn.spring.test;

 

import org.junit.Test;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.context.support.AbstractApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import org.springframework.core.io.ClassPathResource;

 

import www.csdn.spring.dao.impl.HelloDaoImpl;

 

publicclass CycleTest {

 

   @Test

   publicvoid cycleTest() {

      /**

       * bean的生命週期 bean被載入到容器中時,他的生命週期就開始了。bean工廠在一個bean可以使用前完成很多工作:

       * 

       * 1.容器尋找bean的定義資訊並例項化。使用bean工廠或擴充套件的bean工廠context上下文來說明該知識點

       * ClassPathXmlApplicationContext context = new

       * ClassPathXmlApplicationContext("spring-dao.xml");

       * 

       * 2.使用依賴注入,spring按bean定義資訊配置bean的所有屬性。

       * 通過在dao中宣告content屬性並建立setter方法以及spring-dao.xml配置這樣的資訊來說明: <property

       * name="content" value="hello!楊凱!"/>

       * 

       * 3.若bean實現了BeanNameAware介面,工廠呼叫Bean的setBeanName ()方法傳遞bean的ID。

       * 通過dao中的繼承改介面,並實現改介面的相應方法public void setBeanName(String

       * beanId)來說明知識點;重點程式碼在dao中

       * 

       * 4.若bean實現了BeanFactoryAware介面,工廠呼叫setBeanFactory()方法傳入工廠自身。

       * 通過dao中的繼承改介面,並實現改介面的相應方法public void setBeanFactory(BeanFactory

       * factory) throws BeansException 來說明該知識點,重點程式碼在dao中。

       * 

       * 5.若BeanPostProcessor和bean關聯,則它們的

       * postProcessBeforeInitialization()方法被呼叫。

       * 改類是個全域性控局類,只要在一個bean的配置檔案和相應bean類中實現了該介面並重寫了該介面的方法,在整個專案的bean類中都會起作用

       * 所以這裡為了更好說明問題,新建一個BeanPostProcessorImpl類去實現BeanPostProcessor介面

       * 

       * 6.若bean指定了ini-method、destroy-method方法,它將被呼叫。

       * 通過在bean的指定spring配置檔案中配置屬性init-method="init" destroy-method="destroy"

       * 尤其是使destroy-method方法起作用的使用,一定要在測試類中關閉bean工廠物件context.close();

       * 

       * 7.最後,若有BeanPostProcessor和bean關聯,則它們的postProcessAfterInitialization()

       * 方法被呼叫。、同第五個before一樣

       */

 

      /*// 使用上下文context模擬的bean的生命週期:使用ClassPathXmlApplicationContext物件接收

       ClassPathXmlApplicationContext context = new

       ClassPathXmlApplicationContext("spring-dao.xml");

 

       context.getBean("helloDaoImpl",HelloDaoImpl.class).sayHello(); 

      // 執行關閉,以下兩個方法都可以使destory-method的方法的執行

      context.destroy();

      // context.close();

      */

      

      //使用ApplicationContext物件接收,呼叫getBean與上面的方法一樣,不同的是銷燬與關閉的方法需要強轉為AbstractApplicationContext型別的

      ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");

      context.getBean("helloDaoImpl",HelloDaoImpl.class).sayHello(); 

      // 執行關閉,以下兩個方法都可以使destory-method的方法的執行

      //((AbstractApplicationContext) context).destroy();

       ((ConfigurableApplicationContext) context).close();

      

      

       System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=--=-=-=-=-=-==");

       

      /**

       * 除了應用上下文提供的附加功能外,應用上下文與bean工廠的另一個重要區別是關於單例bean 如何被載入。

       * bean工廠延遲載入所有bean,直到getBean() 方法被呼叫。應用上下文會在啟動後預載入所有單例bean.

       * 這樣可確保應用不需要等待他們被建立。

       *  使用bean工廠模擬的bean的生命週期:

       */

      ConfigurableBeanFactory cbf = new XmlBeanFactory(new ClassPathResource("spring-dao.xml"));

      

      /*bean工廠呼叫BeanPostProcessor類的方法也與上下文物件不一樣,上下文物件直接在配置檔案使用bean標籤指明即可,

       * 而在bean工廠中需要下面一個方法去呼叫該類

       */

      //cbf.addBeanPostProcessor(new BeanPostProcessorImpl());

      //這種方法也可以呼叫BeanPostProcessor,與上面結果一樣

      cbf.addBeanPostProcessor(cbf.getBean("beanPostProcessorImpl",BeanPostProcessorImpl.class));

      

      

      //只有使用getBean方法後所有的初始化資訊才會執行

      cbf.getBean("helloDaoImpl",HelloDaoImpl.class);

      //使用下面的方法銷燬所有的單例物件

      cbf.destroySingletons();

   }

}

spring配置檔案的程式碼

<?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">

 

   <!-- spring容器就是負責建立、管理、維護Bean 並且能夠依賴注入到相應元件上 -->

   <bean id="helloDaoImpl" class="www.csdn.spring.dao.impl.HelloDaoImpl"

      scope="singleton" lazy-init="false" init-method="init" destroy-method="destroy">

      <!-- 通過set方法注入 -->

      <property name="content" value="hello!楊凱!" />

   </bean>

 

   <!-- spring-service.xml引用的改配置檔案,所以在前者中加入了lazy-init="false",這裡可以不寫也會起作用;

      lazy-init屬性的意思是:是否延遲載入,就是一建立 spring容器就去例項化對應容器物件,即執行改物件的構造器,而不是在使用的時候才去載入

      lazy-init="false" ,預設的值為default,但是default=false -->

 

   <!-- BeanPostProcessor與當前的bean都進行關聯 -->

   <bean id="beanPostProcessorImpl" class="www.csdn.spring.test.BeanPostProcessorImpl" />

</beans>

bean例項程式碼(這裡把dao做bean講解)

package www.csdn.spring.dao.impl;

 

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.BeanFactoryAware;

import org.springframework.beans.factory.BeanNameAware;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

 

import www.csdn.spring.dao.HelloDao;

 

public class HelloDaoImpl implements HelloDao, BeanNameAware, BeanFactoryAware,

      ApplicationContextAware,InitializingBean {

 

   private String content;

 

   public void setContent(String content) {

      System.out.println("say:setter注入的內容是:" + content);

      this.content = content;

   }

 

   public HelloDaoImpl() {

      System.out.println("HelloDaoImpl例項化。。。。");

   }

 

   @Override

   public void sayHello() {

      System.out.println("say:hello world!");

   }

 

   public void init() {

      System.out.println("----init方法執行了----");

   }

 

   public void destroy() {

      System.out.println("=====destory方法執行了=====");

   }

 

   @Override

   public void setBeanName(String beanId) {

      /*

       * 這裡只能檢視beanId,即使修改也只在改方法內生效,並沒有傳出去,所以在其他方法中使用的beanId還是配置檔案中傳過來的id

       * 而不是被修改過的id;並且這裡只能檢視id,不能使用bean工廠操作,也就是說不能使用傳過來的id去呼叫bean工廠來操作類

       * 更不能使用修改後的id去呼叫bean工廠來操作類

       */

      System.out.println("傳遞bean的ID為:"+beanId);

 

      beanId = "hello";

       System.out.println("修改後的bean的ID為:"+beanId);

   }

 

   @Override

   public void setBeanFactory(BeanFactory factory) throws BeansException {

      /*

       * 這裡可以使用bean工廠執行bean類中的方法的前提是在配置中使用scope="singleton"

       * lazy-init="default" 這兩個屬性才可以達到預期效果,否則控制檯根本不輸出內容

       */

      System.out.println(factory.getClass()+"-----"+factory.getBean("helloDaoImpl"));

       factory.getBean("helloDaoImpl",HelloDaoImpl.class).sayHello();

   }

 

   @Override

   public void setApplicationContext(ApplicationContext applicationContext)

         throws BeansException {

      System.out.println("--呼叫:" + applicationContext);

   }

 

   @Override

   public void afterPropertiesSet() throws Exception {

      System.out.println("----initializingBean介面的方法被呼叫了。。。。");

   }

 

}


 

3.bean的生命週期狀態圖解

     第一個圖中是使用上下文物件通過spring配置檔案來建立、管理、維護的狀態圖解,藍色字型是對比第二張圖的不同之處;第二張圖是bean工廠物件過spring配置檔案來建立、管理、維護的狀態圖解。

4.bean生命週期的UML狀態圖解

     上下文物件

    Bean工廠物件

 

      注:bean在ApplicationContext中的生命週期與BeanFactory中唯一的不同是若實現了ApplicationContextAware()介面則會呼叫setApplicationContext()方法,執行順序是在setBeanFactory()方法之後,預初始化方法之前。

相關文章