中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Bean的生命周期怎么配置

發布時間:2021-12-23 11:30:04 來源:億速云 閱讀:229 作者:iii 欄目:大數據

本篇內容介紹了“Spring Bean的生命周期怎么配置”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

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 生命周期

Spring 只幫我們管理單例模式 Bean 的完整生命周期,對于 prototype 的 bean ,Spring 在創建好交給使用者之后則不會再管理后續的生命周期。

在傳統的 Java 應用中,bean 的生命周期很簡單,使用 Java 關鍵字 new 進行Bean 的實例化,然后該 Bean 就能夠使用了。一旦 bean 不再被使用,則由 Java 自動進行垃圾回收。相比之下,Spring 管理 Bean 的生命周期就復雜多了,正確理解 Bean 的生命周期非常重要,因為 Spring 對 Bean 的管理可擴展性非常強,下面展示了一個 Bean 的構造過程。

Spring Bean的生命周期怎么配置

  1. Spring對bean進行實例化;

  2. Spring將值和bean的引用注入到bean對應的屬性中;

  3. 如果bean實現了BeanNameAware接口,Spring將bean的ID傳遞給 setBean-Name()方法;

  4. 如果bean實現了BeanFactoryAware接口,Spring將調 用setBeanFactory()方法,將BeanFactory容器實例傳入;

  5. 如果bean實現了ApplicationContextAware接口,Spring將調 用setApplicationContext()方法,將bean所在的應用上下文的 引用傳入進來;

  6. 如果bean實現了BeanPostProcessor接口,Spring將調用它們 的post-ProcessBeforeInitialization()方法;

  7. 如果bean實現了InitializingBean接口,Spring將調用它們的 after-PropertiesSet()方法。類似地,如果bean使用init- method聲明了初始化方法,該方法也會被調用;

  8. 如果bean實現了BeanPostProcessor接口,Spring將調用它們 的post-ProcessAfterInitialization()方法;

  9. 此時,bean已經準備就緒,可以被應用程序使用了,它們將一直 駐留在應用上下文中,直到該應用上下文被銷毀;

  10. 如果bean實現了DisposableBean接口,Spring將調用它的 destroy()接口方法。同樣,如果bean使用destroy-method聲明 了銷毀方法,該方法也會被調用。

驗證 Spring Bean 周期

1. singleton

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 也被銷毀。

2. protoType

<?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的生命周期怎么配置”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宜君县| 廉江市| 乌拉特前旗| 唐山市| 全南县| 双峰县| 望谟县| 安宁市| 元阳县| 应城市| 吉安县| 锡林郭勒盟| 宣化县| 永德县| 太湖县| 霸州市| 惠来县| 原平市| 马尔康县| 金山区| 阿克陶县| 石城县| 荥经县| 托克托县| 仁化县| 若羌县| 双鸭山市| 西安市| 唐海县| 清水河县| 惠安县| 临桂县| 桐梓县| 临湘市| 喜德县| 张家界市| 德庆县| 沙洋县| 崇义县| 双辽市| 望都县|