SpringBean的生命周期怎么配置

本篇內(nèi)容介紹了“Spring Bean的生命周期怎么配置”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(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è)要多少錢(qián),請(qǐng)找那個(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容器中只會(huì)存在一個(gè)共享的bean實(shí)例,并且所有對(duì)bean的請(qǐng)求,只要id與該bean定義相匹配,則只會(huì)返回bean的同一實(shí)例。Singleton是單例類(lèi)型,就是在創(chuàng)建起容器時(shí)就同時(shí)自動(dòng)創(chuàng)建了一個(gè)bean的對(duì)象,不管你是否使用,他都存在了,每次獲取到的對(duì)象都是同一個(gè)對(duì)象。注意,Singleton作用域是Spring中的缺省作用域。

  • 當(dāng)一個(gè)bean的作用域?yàn)镻rototype,表示一個(gè)bean定義對(duì)應(yīng)多個(gè)對(duì)象實(shí)例。Prototype作用域的bean會(huì)導(dǎo)致在每次對(duì)該bean請(qǐng)求(將其注入到另一個(gè)bean中,或者以程序的方式調(diào)用容器的getBean()方法)時(shí)都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。Prototype是原型類(lèi)型,它在我們創(chuàng)建容器的時(shí)候并沒(méi)有實(shí)例化,而是當(dāng)我們獲取bean的時(shí)候才會(huì)去創(chuàng)建一個(gè)對(duì)象,而且我們每次獲取到的對(duì)象都不是同一個(gè)對(duì)象。根據(jù)經(jīng)驗(yàn),對(duì)有狀態(tài)的bean應(yīng)該使用prototype作用域,而對(duì)無(wú)狀態(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請(qǐng)求中,一個(gè)bean定義對(duì)應(yīng)一個(gè)實(shí)例;即每個(gè)HTTP請(qǐng)求都會(huì)有各自的bean實(shí)例,它們依據(jù)某個(gè)bean定義創(chuàng)建而成。該作用域僅在基于web的Spring ApplicationContext情形下有效??紤]下面bean定義:

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

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

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

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

針對(duì)某個(gè)HTTP Session,Spring容器會(huì)根據(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í)例,將不會(huì)看到這些特定于某個(gè)HTTP Session的狀態(tài)變化。當(dāng)HTTP Session最終被廢棄的時(shí)候,在該HTTP Session作用域內(nèi)的bean也會(huì)被廢棄掉。

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

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

global session作用域類(lèi)似于標(biāo)準(zhǔn)的HTTP Session作用域,不過(guò)僅僅在基于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 的完整生命周期,對(duì)于 prototype 的 bean ,Spring 在創(chuàng)建好交給使用者之后則不會(huì)再管理后續(xù)的生命周期。

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

Spring Bean的生命周期怎么配置

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

  2. Spring將值和bean的引用注入到bean對(duì)應(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)來(lái);

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

  7. 如果bean實(shí)現(xiàn)了InitializingBean接口,Spring將調(diào)用它們的 after-PropertiesSet()方法。類(lèi)似地,如果bean使用init- method聲明了初始化方法,該方法也會(huì)被調(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)用上下文被銷(xiāo)毀;

  10. 如果bean實(shí)現(xiàn)了DisposableBean接口,Spring將調(diào)用它的 destroy()接口方法。同樣,如果bean使用destroy-method聲明 了銷(xiāo)毀方法,該方法也會(huì)被調(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、開(kāi)始實(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)來(lái)");
    }

    /**
     * 自定義初始化方法
     */
    @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()方法。類(lèi)似地,如果 person 使用 init-"
                + "method 聲明了初始化方法,該方法也會(huì)被調(diào)用");
    }

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

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

    @Override
    public void destroy() throws Exception {
        System.out.println("13、Person 實(shí)現(xiàn)了 DisposableBean 接口,Spring 調(diào)用它的"
                + "destroy() 接口方法。同樣,如果 person 使用 destroy-method 聲明"
                + "了銷(xiāo)毀方法,該方法也會(huì)被調(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í)候會(huì)加載一些其他的 bean,會(huì)調(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è)類(lèi),實(shí)現(xiàn)了接口 BeanPostProcessor 定義的兩個(gè)方法,這兩個(gè)方法分別是:postProcessBeforeInitialization 和 postProcessAfterInitialization,顧名思義,就是分別在 bean 的 init-method 前后進(jìn)行分別執(zhí)行這兩個(gè)方法。多后置處理器的有序性的 bean 在使用的過(guò)程中可以經(jīng)過(guò)多個(gè)后置預(yù)處理的處理,但是,一般情況下,多個(gè)實(shí)現(xiàn)后置處理器接口的類(lèi)是有先后順序的,為了讓 IOC 明白后置處理器之間的先后順序,類(lèi)還要實(shí)現(xiàn) Ordered 接口,通過(guò)接口里的 order 屬性來(lái)控制后處理器的先后順序,默認(rèn)為 0,為最高優(yōu)先級(jí)。同一個(gè)容器中的后置處理器是通用的一個(gè) context 中的后置處理器實(shí)現(xiàn)類(lèi)不是針對(duì)某一個(gè)的 bean,這個(gè) context 中的所有 bean 的產(chǎn)生過(guò)程都回去調(diào)用這個(gè)后置處理器,為了有針對(duì)性,可以通過(guò) bean 的 id 來(lái)執(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)了用戶自定義初始化和銷(xiāo)毀方法 -->
    <bean id="person" class="com.spring.master.spring.bean.lifecycle.Person" init-method="initMethod" destroy-method="destroyMethod">
        <!-- 注入bean 屬性名稱(chēng) -->
        <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生命周期加載過(guò)程
		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、開(kāi)始實(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)來(lái)
6、初始化 Person 之前執(zhí)行的方法
7、@PostConstruct 調(diào)用自定義的初始化方法
8、Person 實(shí)現(xiàn)了 InitializingBean 接口,Spring 調(diào)用它的afterPropertiesSet()方法。類(lèi)似地,如果 person 使用 init-method 聲明了初始化方法,該方法也會(huì)被調(diào)用
9、xml 中聲明的 init-method 方法
10、初始化 Person 完成之后執(zhí)行的方法
11、實(shí)例化完成使用屬性:Person name = HLee
12、@PreDestory 調(diào)用自定義銷(xiāo)毀方法
13、Person 實(shí)現(xiàn)了 DisposableBean 接口,Spring 調(diào)用它的destroy() 接口方法。同樣,如果 person 使用 destroy-method 聲明了銷(xiāo)毀方法,該方法也會(huì)被調(diào)用
14、xml 中聲明的 destroy-method 方法
end---------------destroy-----------------
finalize 方法

當(dāng) person 默認(rèn)是單例模式時(shí),bean 的生命周期與容器的生命周期一樣,容器初始化,bean 也初始化。容器銷(xiāo)毀,bean 也被銷(xiāo)毀。

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)了用戶自定義初始化和銷(xiāo)毀方法 -->
    <bean id="person" scope="prototype" class="com.spring.master.spring.bean.lifecycle.Person" init-method="initMethod" destroy-method="destroyMethod">
        <!-- 注入bean 屬性名稱(chēng) -->
        <property name="name" value="HLee" />
    </bean>

    <!--引入自定義的BeanPostProcessor-->
    <bean class="com.spring.master.spring.bean.lifecycle.PersonBeanPostProcessor"/>

</beans>

輸出:
1、開(kāi)始實(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)來(lái)
6、初始化 Person 之前執(zhí)行的方法
7、@PostConstruct 調(diào)用自定義的初始化方法
8、Person 實(shí)現(xiàn)了 InitializingBean 接口,Spring 調(diào)用它的afterPropertiesSet()方法。類(lèi)似地,如果 person 使用 init-method 聲明了初始化方法,該方法也會(huì)被調(diào)用
9、xml 中聲明的 init-method 方法
10、初始化 Person 完成之后執(zhí)行的方法
11、實(shí)例化完成使用屬性:Person name = HLee
finalize 方法

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

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

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

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

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

廣告

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

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