1. 程式人生 > 其它 >Spring bean生命週期簡介說明

Spring bean生命週期簡介說明

轉發

 http://java265.com/JavaFramework/Spring/202107/504.html

我們都知道,在使用new關鍵字例項化的Java Bean,它的生命週期非常簡單,當Java Bean不需要使用時,則Java會自動進行垃圾回收,
所以它的生命週期會非常容易理解。 
但Spring中Bean的生命週期,則較為複雜,它由Bean定義->Bean初始化->Bean應用->Bean銷燬
Spring 針對不同Bean的作用域採用不同的管理方式
   對採用singleton 作用域Bean,Spring可清楚的知道它的建立及初始化時間及銷燬時間,
但是對於prototype作用域下的Bean,Spring框架則只負責建立,當建立完畢後,則將Bean例項交給客戶端程式碼管理,
Spring將不對此型別的Bean進行生命週期管理 

Spring Bean生命週期執行流程

Spring 容器在確保一個 Bean 能夠使用之前,會進行很多工作。Spring 容器中 Bean 的生命週期流程如下圖所示

Bean 生命週期流程

  1. Spring 啟動,查詢並載入需要被Spring 管理的 Bean,並例項化 Bean。
  2. 利用依賴注入完成 Bean 中所有屬性值的配置注入。
  3. 當Bean 實現了 BeanNameAware 介面,則 Spring 呼叫 Bean 的 setBeanName() 方法傳入當前 Bean 的 id 值。
  4. 當Bean 實現了 BeanFactoryAware 介面,則 Spring 呼叫 setBeanFactory() 方法傳入當前工廠例項的引用。
  5. 當Bean 實現了 ApplicationContextAware 介面,則 Spring 呼叫 setApplicationContext() 方法傳入當前 ApplicationContext 例項的引用。
  6. 當Bean 實現了 BeanPostProcessor 介面,則 Spring 呼叫該介面的預初始化方法 postProcessBeforeInitialzation() 對 Bean 進行加工操作,此處非常重要,Spring 的 AOP 就是利用它實現的。
  7. 當Bean 實現了 InitializingBean 介面,則 Spring 將呼叫 afterPropertiesSet() 方法。
  8. 當在配置檔案中通過 init-method 屬性指定了初始化方法,則呼叫該初始化方法。
  9. 當BeanPostProcessor 和 Bean 關聯,則 Spring 將呼叫該介面的初始化方法 postProcessAfterInitialization()。此時,Bean 已經可以被應用系統使用了。
  10. 當在 <bean> 中指定了該 Bean 的作用域為 singleton,則將該 Bean 放入 Spring IoC 的快取池中,觸發 Spring 對該 Bean 的生命週期管理;如果在 <bean> 中指定了該 Bean 的作用域為 prototype,則將該 Bean 交給呼叫者,呼叫者管理該 Bean 的生命週期,Spring 不再管理該 Bean。
  11. 當Bean 實現了 DisposableBean 介面,則 Spring 會呼叫 destory() 方法銷燬 Bean;如果在配置檔案中通過 destory-method 屬性指定了 Bean 的銷燬方法,則 Spring 將呼叫該方法對 Bean 進行銷燬。


Spring 為 Bean 提供了細緻全面的生命週期過程,實現特定的介面或設定 <bean> 的屬性都可以對 Bean 的生命週期過程產生影響。建議不要過多的使用 Bean 實現介面,因為這樣會導致程式碼的耦合性過高。

瞭解 Spring 生命週期的意義就在於,可以利用 Bean 在其存活期間的指定時刻完成一些相關操作。一般情況下,會在 Bean 被初始化後和被銷燬前執行一些相關操作。

Spring 官方提供了 3 種方法實現初始化回撥和銷燬回撥:

  1. 實現 InitializingBean 和 DisposableBean 介面;
  2. 在 XML 中配置 init-method 和 destory-method;
  3. 使用 @PostConstruct 和 @PreDestory 註解。


在一個 Bean 中有多種生命週期回撥方法時,優先順序為:註解 > 介面 > XML。

不建議使用介面和註解,這會讓 pojo 類和 Spring 框架緊耦合。

初始化回撥

1. 使用介面

org.springframework.beans.factory.InitializingBean 介面提供了以下方法:

  • void afterPropertiesSet() throws Exception;

您可以實現以上介面,在 afterPropertiesSet 方法內指定 Bean 初始化後需要執行的操作。

  <bean id="..." class="..." />
       public class User implements InitializingBean {
        @Override
     public void afterPropertiesSet() throws Exception {
         System.out.println("呼叫介面:InitializingBean,方法:afterPropertiesSet,無引數");
       }
  }

2. 配置XML

可以通過 init-method 屬性指定 Bean 初始化後執行的方法

 <bean id="..." class="..." init-method="init"/>
       public class User {
          public void init() {
             System.out.println("呼叫init-method指定的初始化方法:init" );
         }
     }

3. 使用註解

使用 @PostConstruct 註解標明該方法為 Bean 初始化後的方法。

    
  public class ExampleBean {
         @PostConstruct
        public void init() {
           System.out.println("@PostConstruct註解指定的初始化方法:init" );
        }
      }

銷燬回撥

1. 使用介面

org.springframework.beans.factory.DisposableBean 介面提供了以下方法:

void destroy() throws Exception;

您可以實現以上介面,在 destroy 方法內指定 Bean 初始化後需要執行的操作。

 
     <bean id="..." class="..." />
       public class User implements InitializingBean {
         @Override
       public void afterPropertiesSet() throws Exception {
           System.out.println("呼叫介面:InitializingBean,方法:afterPropertiesSet,無引數");
        }
     }

2. 配置XML

可以通過 destroy-method 屬性指定 Bean 銷燬後執行的方法

    
<bean id="..." class="..." destroy-method="destroy"/>
       public class User {
       public void destroy() {
          System.out.println("呼叫destroy-method指定的銷燬方法:destroy" );
        }
     }

3. 使用註解

使用 @PreDestory 註解標明該方法為 Bean 銷燬前執行的方法。

   public class ExampleBean {
       @PreDestory 
    public void destroy() {
    System.out.println("@PreDestory註解指定的初始化方法:destroy" );
   }
}

下面使用 Eclipse IDE 演示如何通過配置 XML 的方式實現初始化回撥和銷燬回撥,步驟如下:

  1. 建立 SpringDemo 專案,並在 src 目錄下建立 com.java265包。
  2. 新增相應的 jar 包,可以參考《第一個Spring程式》一節。
  3. 在 com.java265 包下建立 HelloWorld 和 MainApp 類。
  4. 在 src 目錄下建立 Spring 配置檔案 Beans.xml。
  5. 執行 SpringDemo 專案


HelloWorld 類-----

package com.java265;
public class HelloWorld {
private String message;

public void setMessage(String message) {
this.message = message;
}
public void getMessage() {
System.out.println("message : " + message);
}
public void init() {
System.out.println("Bean正在進行初始化");
}
public void destroy() {
System.out.println("Bean將要被銷燬");
}
}

MainApp 類程式碼如下,該類中我們使用 AbstractApplicationContext 類的 registerShutdownHook() 方法,來確保正常關機並呼叫相關的 destroy() 方法。

package com.java265;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
context.registerShutdownHook();
}
}

Beans.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-3.0.xsd">

<bean id="helloWorld" class="com.java265.HelloWorld"
init-method="init" destroy-method="destroy">
<property name="message" value="Hello World!" />
</bean>
</beans>

-----執行結果-----

Bean正在進行初始化
message : Hello World!
Bean將要被銷燬

預設的初始化和銷燬方法

如果多個 Bean 需要使用相同的初始化或者銷燬方法,不用為每個 bean 宣告初始化和銷燬方法,可以使用 default-init-method 和 default-destroy-method 屬性,如下:

<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-3.0.xsd"
default-init-method="init"
default-destroy-method="destroy">

<bean id="..." class="...">
...
</bean>
</beans>