您好,登錄后才能下訂單哦!
本篇內容介紹了“Spring Bean的生命周期怎么配置”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
五種作用域中,request、session和global session三種作用域僅在基于web的應用中使用(不必關心你所采用的是什么web應用框架),只能用在基于web的Spring ApplicationContext環境。
當一個bean的作用域為Singleton,那么Spring IoC容器中只會存在一個共享的bean實例,并且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實例。Singleton是單例類型,就是在創建起容器時就同時自動創建了一個bean的對象,不管你是否使用,他都存在了,每次獲取到的對象都是同一個對象。注意,Singleton作用域是Spring中的缺省作用域。
當一個bean的作用域為Prototype,表示一個bean定義對應多個對象實例。Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調用容器的getBean()方法)時都會創建一個新的bean實例。Prototype是原型類型,它在我們創建容器的時候并沒有實例化,而是當我們獲取bean的時候才會去創建一個對象,而且我們每次獲取到的對象都不是同一個對象。根據經驗,對有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。在XML中將bean定義成prototype,可以這樣配置:
<bean id="account" class="com.spring.master.Account" scope="prototype"/> //或者 <bean id="account" class="com.spring.master.Account" singleton="false"/>
當一個bean的作用域為Request,表示在一次HTTP請求中,一個bean定義對應一個實例;即每個HTTP請求都會有各自的bean實例,它們依據某個bean定義創建而成。該作用域僅在基于web的Spring ApplicationContext情形下有效。考慮下面bean定義:
<bean id="loginAction" class=cn.spring.master.LoginAction" scope="request"/>
針對每次HTTP請求,Spring容器會根據loginAction bean的定義創建一個全新的LoginAction bean實例,且該loginAction bean實例僅在當前HTTP request內有效,因此可以根據需要放心的更改所建實例的內部狀態,而其他請求中根據loginAction bean定義創建的實例,將不會看到這些特定于某個請求的狀態變化。當處理請求結束,request作用域的bean實例將被銷毀。
當一個bean的作用域為Session,表示在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基于web的Spring ApplicationContext情形下有效。考慮下面bean定義:
<bean id="userPreferences" class="com.spring.master.UserPreferences" scope="session"/>
針對某個HTTP Session,Spring容器會根據userPreferences bean定義創建一個全新的userPreferences bean實例,且該userPreferences bean僅在當前HTTP Session內有效。與request作用域一樣,可以根據需要放心的更改所創建實例的內部狀態,而別的HTTP Session中根據userPreferences創建的實例,將不會看到這些特定于某個HTTP Session的狀態變化。當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內的bean也會被廢棄掉。
當一個bean的作用域為Global Session,表示在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基于web的Spring ApplicationContext情形下有效。考慮下面bean定義:
<bean id="user" class="com.spring.master.Preferences "scope="globalSession"/>
global session作用域類似于標準的HTTP Session作用域,不過僅僅在基于portlet的web應用中才有意義。Portlet規范定義了全局Session的概念,它被所有構成某個portlet web應用的各種不同的portlet所共享。在global session作用域中定義的bean被限定于全局portlet Session的生命周期范圍內。
Spring 只幫我們管理單例模式 Bean 的完整生命周期,對于 prototype 的 bean ,Spring 在創建好交給使用者之后則不會再管理后續的生命周期。
在傳統的 Java 應用中,bean 的生命周期很簡單,使用 Java 關鍵字 new 進行Bean 的實例化,然后該 Bean 就能夠使用了。一旦 bean 不再被使用,則由 Java 自動進行垃圾回收。相比之下,Spring 管理 Bean 的生命周期就復雜多了,正確理解 Bean 的生命周期非常重要,因為 Spring 對 Bean 的管理可擴展性非常強,下面展示了一個 Bean 的構造過程。
Spring對bean進行實例化;
Spring將值和bean的引用注入到bean對應的屬性中;
如果bean實現了BeanNameAware接口,Spring將bean的ID傳遞給 setBean-Name()方法;
如果bean實現了BeanFactoryAware接口,Spring將調 用setBeanFactory()方法,將BeanFactory容器實例傳入;
如果bean實現了ApplicationContextAware接口,Spring將調 用setApplicationContext()方法,將bean所在的應用上下文的 引用傳入進來;
如果bean實現了BeanPostProcessor接口,Spring將調用它們 的post-ProcessBeforeInitialization()方法;
如果bean實現了InitializingBean接口,Spring將調用它們的 after-PropertiesSet()方法。類似地,如果bean使用init- method聲明了初始化方法,該方法也會被調用;
如果bean實現了BeanPostProcessor接口,Spring將調用它們 的post-ProcessAfterInitialization()方法;
此時,bean已經準備就緒,可以被應用程序使用了,它們將一直 駐留在應用上下文中,直到該應用上下文被銷毀;
如果bean實現了DisposableBean接口,Spring將調用它的 destroy()接口方法。同樣,如果bean使用destroy-method聲明 了銷毀方法,該方法也會被調用。
package com.spring.master.spring.bean.lifecycle; import org.springframework.beans.BeansException; import org.springframework.beans.factory.*; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; /** * @author Huan Lee * @version 1.0 * @date 2020-09-23 11:02 * @describtion 業精于勤,荒于嬉;行成于思,毀于隨。 */ public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean { private String name; public Person(){ System.out.println("1、開始實例化 person "); } public String getName() { return name; } public void setName(String name) { this.name = name; System.out.println("2、設置 name 屬性"); } @Override public void setBeanName(String beanId) { System.out.println("3、Person 實現了 BeanNameAware 接口,Spring 將 Person 的 " + "ID=" + beanId + "傳遞給 setBeanName 方法"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("4、Person 實現了 BeanFactoryAware 接口,Spring 調" + "用 setBeanFactory()方法,將 BeanFactory 容器實例傳入"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("5、Person 實現了 ApplicationContextAware 接口,Spring 調" + "用 setApplicationContext()方法,將 person 所在的應用上下文的" + "引用傳入進來"); } /** * 自定義初始化方法 */ @PostConstruct public void springPostConstruct(){ System.out.println("7、@PostConstruct 調用自定義的初始化方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("8、Person 實現了 InitializingBean 接口,Spring 調用它的" + "afterPropertiesSet()方法。類似地,如果 person 使用 init-" + "method 聲明了初始化方法,該方法也會被調用"); } /** * xml 中聲明的 init-method 方法 */ public void initMethod(){ System.out.println("9、xml 中聲明的 init-method 方法"); } /** * 自定義銷毀方法 */ @PreDestroy public void springPreDestory(){ System.out.println("12、@PreDestory 調用自定義銷毀方法"); } @Override public void destroy() throws Exception { System.out.println("13、Person 實現了 DisposableBean 接口,Spring 調用它的" + "destroy() 接口方法。同樣,如果 person 使用 destroy-method 聲明" + "了銷毀方法,該方法也會被調用"); } /** * xml 中聲明的 destroy-method 方法 */ public void destroyMethod(){ System.out.println("14、xml 中聲明的 destroy-method 方法"); System.out.println("end---------------destroy-----------------"); } @Override protected void finalize() throws Throwable { System.out.println("finalize 方法"); } }
package com.spring.master.spring.bean.lifecycle; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** * @author Huan Lee * @version 1.0 * @date 2020-09-23 11:31 * @describtion 后置處理器 */ public class PersonBeanPostProcessor implements BeanPostProcessor { // 容器加載的時候會加載一些其他的 bean,會調用初始化前和初始化后方法 // 這次只關注 Person 的生命周期 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof Person){ System.out.println("6、初始化 Person 之前執行的方法"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof Person){ System.out.println("10、初始化 Person 完成之后執行的方法"); } return bean; } }
后置處理器是什么?
一個類,實現了接口 BeanPostProcessor 定義的兩個方法,這兩個方法分別是:postProcessBeforeInitialization 和 postProcessAfterInitialization,顧名思義,就是分別在 bean 的 init-method 前后進行分別執行這兩個方法。多后置處理器的有序性的 bean 在使用的過程中可以經過多個后置預處理的處理,但是,一般情況下,多個實現后置處理器接口的類是有先后順序的,為了讓 IOC 明白后置處理器之間的先后順序,類還要實現 Ordered 接口,通過接口里的 order 屬性來控制后處理器的先后順序,默認為 0,為最高優先級。同一個容器中的后置處理器是通用的一個 context 中的后置處理器實現類不是針對某一個的 bean,這個 context 中的所有 bean 的產生過程都回去調用這個后置處理器,為了有針對性,可以通過 bean 的 id 來執行特異話的操作。
resource 文件夾下新建一個 bean_lifecycle.xml 文件注入相關 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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 掃描bean --> <context:component-scan base-package="com.spring.master.spring.bean.lifecycle"/> <!-- 實現了用戶自定義初始化和銷毀方法 --> <bean id="person" class="com.spring.master.spring.bean.lifecycle.Person" init-method="initMethod" destroy-method="destroyMethod"> <!-- 注入bean 屬性名稱 --> <property name="name" value="HLee" /> </bean> <!--引入自定義的BeanPostProcessor--> <bean class="com.spring.master.spring.bean.lifecycle.PersonBeanPostProcessor"/> </beans>
package com.spring.master; import com.spring.master.spring.bean.lifecycle.Person; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @SpringBootApplication public class SpringMasterApplication { public static void main(String[] args) { SpringApplication.run(SpringMasterApplication.class, args); // 為面試而準備的Bean生命周期加載過程 ApplicationContext context = new ClassPathXmlApplicationContext("bean_lifecycle.xml"); Person person = (Person)context.getBean("person"); // 使用屬性 System.out.println("11、實例化完成使用屬性:Person name = " + person.getName()); // 關閉容器 ((ClassPathXmlApplicationContext) context).close(); } } 輸出結果: 1、開始實例化 person 2、設置 name 屬性 3、Person 實現了 BeanNameAware 接口,Spring 將 Person 的 ID=person傳遞給 setBeanName 方法 4、Person 實現了 BeanFactoryAware 接口,Spring 調用 setBeanFactory()方法,將 BeanFactory 容器實例傳入 5、Person 實現了 ApplicationContextAware 接口,Spring 調用 setApplicationContext()方法,將 person 所在的應用上下文的引用傳入進來 6、初始化 Person 之前執行的方法 7、@PostConstruct 調用自定義的初始化方法 8、Person 實現了 InitializingBean 接口,Spring 調用它的afterPropertiesSet()方法。類似地,如果 person 使用 init-method 聲明了初始化方法,該方法也會被調用 9、xml 中聲明的 init-method 方法 10、初始化 Person 完成之后執行的方法 11、實例化完成使用屬性:Person name = HLee 12、@PreDestory 調用自定義銷毀方法 13、Person 實現了 DisposableBean 接口,Spring 調用它的destroy() 接口方法。同樣,如果 person 使用 destroy-method 聲明了銷毀方法,該方法也會被調用 14、xml 中聲明的 destroy-method 方法 end---------------destroy----------------- finalize 方法 當 person 默認是單例模式時,bean 的生命周期與容器的生命周期一樣,容器初始化,bean 也初始化。容器銷毀,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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 掃描bean --> <context:component-scan base-package="com.spring.master.spring.bean.lifecycle"/> <!-- 實現了用戶自定義初始化和銷毀方法 --> <bean id="person" scope="prototype" class="com.spring.master.spring.bean.lifecycle.Person" init-method="initMethod" destroy-method="destroyMethod"> <!-- 注入bean 屬性名稱 --> <property name="name" value="HLee" /> </bean> <!--引入自定義的BeanPostProcessor--> <bean class="com.spring.master.spring.bean.lifecycle.PersonBeanPostProcessor"/> </beans> 輸出: 1、開始實例化 person 2、設置 name 屬性 3、Person 實現了 BeanNameAware 接口,Spring 將 Person 的 ID=person傳遞給 setBeanName 方法 4、Person 實現了 BeanFactoryAware 接口,Spring 調用 setBeanFactory()方法,將 BeanFactory 容器實例傳入 5、Person 實現了 ApplicationContextAware 接口,Spring 調用 setApplicationContext()方法,將 person 所在的應用上下文的引用傳入進來 6、初始化 Person 之前執行的方法 7、@PostConstruct 調用自定義的初始化方法 8、Person 實現了 InitializingBean 接口,Spring 調用它的afterPropertiesSet()方法。類似地,如果 person 使用 init-method 聲明了初始化方法,該方法也會被調用 9、xml 中聲明的 init-method 方法 10、初始化 Person 完成之后執行的方法 11、實例化完成使用屬性:Person name = HLee finalize 方法
此時,容器關閉,person 對象并沒有銷毀。原因在于,單實例模式下,bean 的生命周期由容器管理,容器生,bean 生;容器死,bean 死。而在多實例模式下,Spring 就管不了那么多了,bean 的生命周期,交由客戶端也就是程序員或者 JVM 來進行管理。
備注:修改對應的xml即可
“Spring Bean的生命周期怎么配置”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。