SpringBean的生命周期怎么配置

本篇內(nèi)容介紹了“Spring Bean的生命周期怎么配置”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

永年網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),永年網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為永年1000多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個(gè)售后服務(wù)好的永年做網(wǎng)站的公司定做!

Bean的作用域

五種作用域中,request、session和global session三種作用域僅在基于web的應(yīng)用中使用(不必關(guān)心你所采用的是什么web應(yīng)用框架),只能用在基于web的Spring ApplicationContext環(huán)境。

  • 當(dāng)一個(gè)bean的作用域?yàn)镾ingleton,那么Spring IoC容器中只會存在一個(gè)共享的bean實(shí)例,并且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實(shí)例。Singleton是單例類型,就是在創(chuàng)建起容器時(shí)就同時(shí)自動創(chuàng)建了一個(gè)bean的對象,不管你是否使用,他都存在了,每次獲取到的對象都是同一個(gè)對象。注意,Singleton作用域是Spring中的缺省作用域。

  • 當(dāng)一個(gè)bean的作用域?yàn)镻rototype,表示一個(gè)bean定義對應(yīng)多個(gè)對象實(shí)例。Prototype作用域的bean會導(dǎo)致在每次對該bean請求(將其注入到另一個(gè)bean中,或者以程序的方式調(diào)用容器的getBean()方法)時(shí)都會創(chuàng)建一個(gè)新的bean實(shí)例。Prototype是原型類型,它在我們創(chuàng)建容器的時(shí)候并沒有實(shí)例化,而是當(dāng)我們獲取bean的時(shí)候才會去創(chuàng)建一個(gè)對象,而且我們每次獲取到的對象都不是同一個(gè)對象。根據(jù)經(jīng)驗(yàn),對有狀態(tài)的bean應(yīng)該使用prototype作用域,而對無狀態(tài)的bean則應(yīng)該使用singleton作用域。在XML中將bean定義成prototype,可以這樣配置:

<bean id="account" class="com.spring.master.Account" scope="prototype"/>  
 //或者
<bean id="account" class="com.spring.master.Account" singleton="false"/>
  • 當(dāng)一個(gè)bean的作用域?yàn)镽equest,表示在一次HTTP請求中,一個(gè)bean定義對應(yīng)一個(gè)實(shí)例;即每個(gè)HTTP請求都會有各自的bean實(shí)例,它們依據(jù)某個(gè)bean定義創(chuàng)建而成。該作用域僅在基于web的Spring ApplicationContext情形下有效??紤]下面bean定義:

<bean id="loginAction" class=cn.spring.master.LoginAction" scope="request"/>

針對每次HTTP請求,Spring容器會根據(jù)loginAction bean的定義創(chuàng)建一個(gè)全新的LoginAction bean實(shí)例,且該loginAction bean實(shí)例僅在當(dāng)前HTTP request內(nèi)有效,因此可以根據(jù)需要放心的更改所建實(shí)例的內(nèi)部狀態(tài),而其他請求中根據(jù)loginAction bean定義創(chuàng)建的實(shí)例,將不會看到這些特定于某個(gè)請求的狀態(tài)變化。當(dāng)處理請求結(jié)束,request作用域的bean實(shí)例將被銷毀。

  • 當(dāng)一個(gè)bean的作用域?yàn)镾ession,表示在一個(gè)HTTP Session中,一個(gè)bean定義對應(yīng)一個(gè)實(shí)例。該作用域僅在基于web的Spring ApplicationContext情形下有效??紤]下面bean定義:

<bean id="userPreferences" class="com.spring.master.UserPreferences" scope="session"/>

針對某個(gè)HTTP Session,Spring容器會根據(jù)userPreferences bean定義創(chuàng)建一個(gè)全新的userPreferences bean實(shí)例,且該userPreferences bean僅在當(dāng)前HTTP Session內(nèi)有效。與request作用域一樣,可以根據(jù)需要放心的更改所創(chuàng)建實(shí)例的內(nèi)部狀態(tài),而別的HTTP Session中根據(jù)userPreferences創(chuàng)建的實(shí)例,將不會看到這些特定于某個(gè)HTTP Session的狀態(tài)變化。當(dāng)HTTP Session最終被廢棄的時(shí)候,在該HTTP Session作用域內(nèi)的bean也會被廢棄掉。

  • 當(dāng)一個(gè)bean的作用域?yàn)镚lobal Session,表示在一個(gè)全局的HTTP Session中,一個(gè)bean定義對應(yīng)一個(gè)實(shí)例。典型情況下,僅在使用portlet context的時(shí)候有效。該作用域僅在基于web的Spring ApplicationContext情形下有效??紤]下面bean定義:

<bean id="user" class="com.spring.master.Preferences "scope="globalSession"/>

global session作用域類似于標(biāo)準(zhǔn)的HTTP Session作用域,不過僅僅在基于portlet的web應(yīng)用中才有意義。Portlet規(guī)范定義了全局Session的概念,它被所有構(gòu)成某個(gè)portlet web應(yīng)用的各種不同的portlet所共享。在global session作用域中定義的bean被限定于全局portlet Session的生命周期范圍內(nèi)。

Spring 生命周期

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

在傳統(tǒng)的 Java 應(yīng)用中,bean 的生命周期很簡單,使用 Java 關(guān)鍵字 new 進(jìn)行Bean 的實(shí)例化,然后該 Bean 就能夠使用了。一旦 bean 不再被使用,則由 Java 自動進(jìn)行垃圾回收。相比之下,Spring 管理 Bean 的生命周期就復(fù)雜多了,正確理解 Bean 的生命周期非常重要,因?yàn)?Spring 對 Bean 的管理可擴(kuò)展性非常強(qiáng),下面展示了一個(gè) Bean 的構(gòu)造過程。

Spring Bean的生命周期怎么配置

  1. Spring對bean進(jìn)行實(shí)例化;

  2. Spring將值和bean的引用注入到bean對應(yīng)的屬性中;

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

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

  5. 如果bean實(shí)現(xiàn)了ApplicationContextAware接口,Spring將調(diào) 用setApplicationContext()方法,將bean所在的應(yīng)用上下文的 引用傳入進(jìn)來;

  6. 如果bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們 的post-ProcessBeforeInitialization()方法;

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

  8. 如果bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們 的post-ProcessAfterInitialization()方法;

  9. 此時(shí),bean已經(jīng)準(zhǔn)備就緒,可以被應(yīng)用程序使用了,它們將一直 駐留在應(yīng)用上下文中,直到該應(yīng)用上下文被銷毀;

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

驗(yàn)證 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 業(yè)精于勤,荒于嬉;行成于思,毀于隨。
 */
public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private String name;

    public Person(){
        System.out.println("1、開始實(shí)例化 person ");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("2、設(shè)置 name 屬性");
    }

    @Override
    public void setBeanName(String beanId) {
        System.out.println("3、Person 實(shí)現(xiàn)了 BeanNameAware 接口,Spring 將 Person 的 "
                + "ID=" + beanId + "傳遞給 setBeanName 方法");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("4、Person 實(shí)現(xiàn)了 BeanFactoryAware 接口,Spring 調(diào)"
                + "用 setBeanFactory()方法,將 BeanFactory 容器實(shí)例傳入");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("5、Person 實(shí)現(xiàn)了 ApplicationContextAware 接口,Spring 調(diào)"
                + "用 setApplicationContext()方法,將 person 所在的應(yīng)用上下文的"
                + "引用傳入進(jìn)來");
    }

    /**
     * 自定義初始化方法
     */
    @PostConstruct
    public void springPostConstruct(){
        System.out.println("7、@PostConstruct 調(diào)用自定義的初始化方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("8、Person 實(shí)現(xiàn)了 InitializingBean 接口,Spring 調(diào)用它的"
                + "afterPropertiesSet()方法。類似地,如果 person 使用 init-"
                + "method 聲明了初始化方法,該方法也會被調(diào)用");
    }

    /**
     * xml 中聲明的 init-method 方法
     */
    public void initMethod(){
        System.out.println("9、xml 中聲明的 init-method 方法");
    }

    /**
     * 自定義銷毀方法
     */
    @PreDestroy
    public void springPreDestory(){
        System.out.println("12、@PreDestory 調(diào)用自定義銷毀方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("13、Person 實(shí)現(xiàn)了 DisposableBean 接口,Spring 調(diào)用它的"
                + "destroy() 接口方法。同樣,如果 person 使用 destroy-method 聲明"
                + "了銷毀方法,該方法也會被調(diào)用");
    }

    /**
     * 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 {


    // 容器加載的時(shí)候會加載一些其他的 bean,會調(diào)用初始化前和初始化后方法
    // 這次只關(guān)注 Person 的生命周期
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Person){
            System.out.println("6、初始化 Person 之前執(zhí)行的方法");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof Person){
            System.out.println("10、初始化 Person 完成之后執(zhí)行的方法");
        }
        return bean;
    }
}

后置處理器是什么?

一個(gè)類,實(shí)現(xiàn)了接口 BeanPostProcessor 定義的兩個(gè)方法,這兩個(gè)方法分別是:postProcessBeforeInitialization 和 postProcessAfterInitialization,顧名思義,就是分別在 bean 的 init-method 前后進(jìn)行分別執(zhí)行這兩個(gè)方法。多后置處理器的有序性的 bean 在使用的過程中可以經(jīng)過多個(gè)后置預(yù)處理的處理,但是,一般情況下,多個(gè)實(shí)現(xiàn)后置處理器接口的類是有先后順序的,為了讓 IOC 明白后置處理器之間的先后順序,類還要實(shí)現(xiàn) Ordered 接口,通過接口里的 order 屬性來控制后處理器的先后順序,默認(rèn)為 0,為最高優(yōu)先級。同一個(gè)容器中的后置處理器是通用的一個(gè) context 中的后置處理器實(shí)現(xiàn)類不是針對某一個(gè)的 bean,這個(gè) context 中的所有 bean 的產(chǎn)生過程都回去調(diào)用這個(gè)后置處理器,為了有針對性,可以通過 bean 的 id 來執(zhí)行特異話的操作。 

resource 文件夾下新建一個(gè) bean_lifecycle.xml 文件注入相關(guān) 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"/>

    <!-- 實(shí)現(xiàn)了用戶自定義初始化和銷毀方法 -->
    <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);

		// 為面試而準(zhǔn)備的Bean生命周期加載過程
		ApplicationContext context = new ClassPathXmlApplicationContext("bean_lifecycle.xml");
		Person person = (Person)context.getBean("person");
		// 使用屬性
		System.out.println("11、實(shí)例化完成使用屬性:Person name = " + person.getName());
		// 關(guān)閉容器
		((ClassPathXmlApplicationContext) context).close();

	}

}

輸出結(jié)果:
1、開始實(shí)例化 person 
2、設(shè)置 name 屬性
3、Person 實(shí)現(xiàn)了 BeanNameAware 接口,Spring 將 Person 的 ID=person傳遞給 setBeanName 方法
4、Person 實(shí)現(xiàn)了 BeanFactoryAware 接口,Spring 調(diào)用 setBeanFactory()方法,將 BeanFactory 容器實(shí)例傳入
5、Person 實(shí)現(xiàn)了 ApplicationContextAware 接口,Spring 調(diào)用 setApplicationContext()方法,將 person 所在的應(yīng)用上下文的引用傳入進(jìn)來
6、初始化 Person 之前執(zhí)行的方法
7、@PostConstruct 調(diào)用自定義的初始化方法
8、Person 實(shí)現(xiàn)了 InitializingBean 接口,Spring 調(diào)用它的afterPropertiesSet()方法。類似地,如果 person 使用 init-method 聲明了初始化方法,該方法也會被調(diào)用
9、xml 中聲明的 init-method 方法
10、初始化 Person 完成之后執(zhí)行的方法
11、實(shí)例化完成使用屬性:Person name = HLee
12、@PreDestory 調(diào)用自定義銷毀方法
13、Person 實(shí)現(xiàn)了 DisposableBean 接口,Spring 調(diào)用它的destroy() 接口方法。同樣,如果 person 使用 destroy-method 聲明了銷毀方法,該方法也會被調(diào)用
14、xml 中聲明的 destroy-method 方法
end---------------destroy-----------------
finalize 方法

當(dāng) person 默認(rèn)是單例模式時(shí),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"/>

    <!-- 實(shí)現(xiàn)了用戶自定義初始化和銷毀方法 -->
    <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、開始實(shí)例化 person 
2、設(shè)置 name 屬性
3、Person 實(shí)現(xiàn)了 BeanNameAware 接口,Spring 將 Person 的 ID=person傳遞給 setBeanName 方法
4、Person 實(shí)現(xiàn)了 BeanFactoryAware 接口,Spring 調(diào)用 setBeanFactory()方法,將 BeanFactory 容器實(shí)例傳入
5、Person 實(shí)現(xiàn)了 ApplicationContextAware 接口,Spring 調(diào)用 setApplicationContext()方法,將 person 所在的應(yīng)用上下文的引用傳入進(jìn)來
6、初始化 Person 之前執(zhí)行的方法
7、@PostConstruct 調(diào)用自定義的初始化方法
8、Person 實(shí)現(xiàn)了 InitializingBean 接口,Spring 調(diào)用它的afterPropertiesSet()方法。類似地,如果 person 使用 init-method 聲明了初始化方法,該方法也會被調(diào)用
9、xml 中聲明的 init-method 方法
10、初始化 Person 完成之后執(zhí)行的方法
11、實(shí)例化完成使用屬性:Person name = HLee
finalize 方法

此時(shí),容器關(guān)閉,person 對象并沒有銷毀。原因在于,單實(shí)例模式下,bean 的生命周期由容器管理,容器生,bean 生;容器死,bean 死。而在多實(shí)例模式下,Spring 就管不了那么多了,bean 的生命周期,交由客戶端也就是程序員或者 JVM 來進(jìn)行管理。

備注:修改對應(yīng)的xml即可

“Spring Bean的生命周期怎么配置”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

網(wǎng)站題目:SpringBean的生命周期怎么配置
分享路徑:http://muchs.cn/article22/iicdcc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、App開發(fā)網(wǎng)站收錄、定制網(wǎng)站、面包屑導(dǎo)航電子商務(wù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名