国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot:詳解Bean生命周期和作用域

這篇具有很好參考價值的文章主要介紹了SpringBoot:詳解Bean生命周期和作用域。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC

??浩澤學編程:個人主頁

??? 推薦專欄:《深入淺出SpringBoot》《java項目分享》
??????????????《RabbitMQ》《Spring》《SpringMVC》
??學無止境,不驕不躁,知行合一

前言

前面我們講訴了將Bean正確地裝配到IoC容器,卻未講訴IoC如何裝配和銷毀Bean。本篇文章主要講訴一下Bean的生命周期和作用域。


一、生命周期

  • Bean 的生命周期的過程, 它大致分為Bean定義、Bean 的初始化、 Bean 的生存期和 Bean 的銷毀4個部分。 其中 Bean 定義過程大致如下:

    • Spring 通過我們的配置,如@ComponentScan 定義的掃描路徑去找到帶有@Component 的類,
      這個過程就是一個資源定位的過程。
    • 一旦找到了資源,那么它就開始解析,并且將定義的信息保存起來。注意,此時還沒有初始
      化Bean,也就沒有Bean 的實例,它有的僅僅是Bean 的定義
      。
    • 然后就會把Bean 定義發(fā)布到 Spring IoC 容器中。 此時, IoC 容器也只有Bean 的定義,還是
      沒有Bean 的實例生成
      。
  • 完成了這3 步只是一個資源定位并將Bean 的定義發(fā)布到IoC容器的過程,還沒有Bean實例的生成,更沒有完成依賴注入。在默認的情況下, Spring會繼續(xù)去完成Bean 的實例化和依賴注入,這樣從IoC 容器中就可以得到一個依賴注入完成的Bean。 但是,有些Bean會受到變化因素的影響,這時我們倒希望是取出 Bean 的時候完成初始化和依賴注入,換句話說就是讓那些 Bean 只是將定義發(fā)布到IoC 容器而不做實例化和依賴注入, 當我們取出來的時候才做初始化和依賴注入等操作。

Spring Bean的初始化過程:
SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC
ComponentScan 中還有一個配置項 lazyI nit,只可以配置 Boolean 值,且默認值為 false,也就是默認不進行延遲初始化,因此在默認的情況下Spring會對Bean進行實例化和依賴注入對應的屬性值。

引入例子:人類(Person)有時候利用一些動物(Animal)去完成一些事情,比方說狗(Dog)是用來看門的,貓(Cat)是用來抓老鼠的.。

代碼如下:

//定義人類接口
public interface Person {
    void service();

    void setAnimal(Animal animal);
}
//定義動物接口
public interface Animal {
    void user();
}
//定義狗
@Component
public class Dog implements Animal {
    @Override
    public void user() {
        System.out.println("狗【" + Dog.class.getSimpleName() + "】是用來看門的");
    }
}
//定義年輕人
@Component
public class YoungPerson implements Person {
    @Autowired
    private Animal animal = null;

    @Override
    public void service() {
        this.animal.user();
    }

    @Override
    public void setAnimal(Animal animal) {
        this.animal = animal;
    }
}
//定義貓
@Component
public class Cat implements Animal{
    @Override
    public void user() {
        System.out.println("貓【" + Cat.class.getSimpleName() + "】是抓老鼠的");
    }
}

//定義配置類
@Configuration
@ComponentScan("com.dragon.restart")//所有的包和類都在restart下
public class AppConfig {
}

此時沒有配置lazyInit的情況進行斷點測試如下:
SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC
可以看到在斷點處,我們并沒有獲取Bean 的實例,而日志就已經(jīng)打出了,可見它是在SpringIoC容器初
始化時就執(zhí)行了實例化和依賴注入。為了改變這個情況,我們在配置類AppConfig的@ComponentScan
中加入lazylnit 配置,如下面的代碼:

@Configuration
@ComponentScan(value = "com.dragon.restart",lazyInit = true)
public class AppConfig {
}

SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC
SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC

就可以發(fā)現(xiàn)在斷點處“延遲依賴注入”這行并不會出現(xiàn)在日志中,只有運行過斷點處才會出現(xiàn)這行日志,這是因為我們把它修改為了延遲初始化, Spring并不會在發(fā)布Bean定義后馬上為我們完成實例化和依賴注入。

如果僅僅是實例化和依賴注入還是比較簡單的,還不能完成進行自定義的要求。 為了完成依賴注入的功能, Spring 在完成依賴注入之后,還提供了一系列的接口和配置來完成Bean初始化的過程,讓我們學習這個過程。 Spring在完成依賴注入后,還會進行如下圖所示流程來完成它的生命周期:
SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC

圖中描述的是整個IoC容器初始化Bean 的流程,作為開發(fā)者,需要注意這些流程。除此之外,還需要注意以下兩點:

  • 這些接口和方法是針對什么而言的。 對于上圖, 在沒有注釋的情況下的流程節(jié)點都是針對單個Bean 而言的,但是BeanPostProcessor 是針對所有 Bean 而言的,這是我們需要注意的地方。
  • 即使你定義了 ApplicationContextAware 接口,但是有時候并不會調用,這要根據(jù)你的 IoC 容器來決定。 我們知道, Spring IoC 容器最低的要求是實現(xiàn) BeanFactory 接口,而不是實現(xiàn)ApplicationContext 接口 。 對于那些沒有實現(xiàn) ApplicationContext 接口的容器,在生命周期對應的ApplicationContextAware 定義的方法也是不會被調用的,只有實現(xiàn)了 ApplicationContext 接口的容器,才會在生命周期調用 ApplicationContextAware 所定義的 setApplicationContext方法。

現(xiàn)在改造一下YoungPerson類:

@Component
public class YoungPerson implements Person, BeanNameAware , BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
    private Animal animal = null;

    @Override
    public void service() {
        this.animal.user();
    }
    @Autowired
    @Qualifier("dog")
    @Override
    public void setAnimal(Animal animal) {
        System.out.println("延遲依賴注入");
        this.animal = animal;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println ("【" + this.getClass().getSimpleName() + "】調用BeanNameAware的setBeanName");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println ("【" + this.getClass().getSimpleName() + "】調用BeanFactoryAware的setBeanFactory");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println ("【" + this.getClass().getSimpleName() + "】調用DisposableBean方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println ("【" + this.getClass().getSimpleName() + "】調用InitializingBean方法的afterPropertiesSet方法");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println ("【" + this.getClass().getSimpleName() + "】調用ApplicationContextAware方法的setApplicationContext方法");
    }
    @PostConstruct
    public void init () {
        System.out.println("【" + this.getClass().getSimpleName() + "】注解@PostConstruct定義的自定義初始化方法");
    }
    @PreDestroy
    public void destroyl () {
        System.out.println("【" + this.getClass().getSimpleName() + "】注解@PreDestroy定義的自定義銷毀方法");
    }
}

這樣,這個 B巳an 就實現(xiàn)了生命周期中單個 Bean 可以實現(xiàn)的所有接口, 并且通過注解@PostConstruct 定義了初始化方法,通過注解@PreDestroy 定義了銷毀方法。 為了測試 Bean 的后置處理器, 這里創(chuàng)建一個類BeanPostProcessorExampIe,如下:

/**
 * @Version: 1.0.0
 * @Author: Dragon_王
 * @ClassName: BeanPostProcessorExample
 * @Description: TODO描述
 * @Date: 2024/1/20 23:34
 */
public class BeanPostProcessorExample implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor調用"+
                "postProcessBeforeinitialization方法,參數(shù)【"+
                bean.getClass().getSimpleName()+"】【"+beanName+"】");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor調用"+
                "postProcessAfterinitialization方法,參數(shù)【"+
                bean.getClass().getSimpleName()+"】【"+beanName+"】");
        return bean;
    }
}

注意,這個Bean后置處理器將對所有的Bean有效,運行測試如下:
測試類:

AnnotationConfigApplicationContext ctx =new AnnotationConfigApplicationContext(AppConfig.class) ;
		ctx.close();
2024-01-20T23:43:23.135+08:00  INFO 748 --- [           main] c.d.restart.RestartApplicationTests      : Starting RestartApplicationTests using Java 19 with PID 748 (started by ThundeRobot in E:\IDEA_projects\restart)
2024-01-20T23:43:23.136+08:00  INFO 748 --- [           main] c.d.restart.RestartApplicationTests      : No active profile set, falling back to 1 default profile: "default"
BeanPostProcessor調用postProcessBeforeinitialization方法,參數(shù)【RestartApplication$$SpringCGLIB$$0】【restartApplication】
BeanPostProcessor調用postProcessAfterinitialization方法,參數(shù)【RestartApplication$$SpringCGLIB$$0】【restartApplication】
BeanPostProcessor調用postProcessBeforeinitialization方法,參數(shù)【AppConfig$$SpringCGLIB$$0】【appConfig】
BeanPostProcessor調用postProcessAfterinitialization方法,參數(shù)【AppConfig$$SpringCGLIB$$0】【appConfig】
BeanPostProcessor調用postProcessBeforeinitialization方法,參數(shù)【Cat】【cat】
BeanPostProcessor調用postProcessAfterinitialization方法,參數(shù)【Cat】【cat】
BeanPostProcessor調用postProcessBeforeinitialization方法,參數(shù)【Dog】【dog】
BeanPostProcessor調用postProcessAfterinitialization方法,參數(shù)【Dog】【dog】
延遲依賴注入
【YoungPerson】調用BeanNameAware的setBeanName
【YoungPerson】調用BeanFactoryAware的setBeanFactory
【YoungPerson】調用ApplicationContextAware方法的setApplicationContext方法
BeanPostProcessor調用postProcessBeforeinitialization方法,參數(shù)【YoungPerson】【youngPerson】
【YoungPerson】注解@PostConstruct定義的自定義初始化方法
【YoungPerson】調用InitializingBean方法的afterPropertiesSet方法
BeanPostProcessor調用postProcessAfterinitialization方法,參數(shù)【YoungPerson】【youngPerson】
BeanPostProcessor 調用 postProcessBeforeinitialization 方法,參數(shù) 【Cat】【cat】
 BeanPostProcessor 調用 postProcessAfterinitialization 方法, 參數(shù) 【Cat】【cat】
 2024-01-20T23:43:24.044+08:00  INFO 748 --- [main] c.d.restart.RestartApplicationTests      : Started RestartApplicationTests in 1.142 seconds (process running for 1.772)YoungPerson】注解@PreDestroy定義的自定義銷毀方法
【YoungPerson】調用DisposableBean方法

從日志可以看出,對于Bean后置處理器(BeanPostProcessor)而言, 它對所有的 Bean 都起作用,而其他的接口則是對于單個Bean起作用。我們還可以注意到BussinessPerson執(zhí)行的流程是上圖所畫出的流程。有時候Bean 的定義可能使用的是第三方的類,此時可以使用注解@Bean來配置自定義初始化和銷毀方法,如下所示:

@Bean(InitMethod =”Init”, destroyMethod = ”destroy” )

二、作用域

在介紹IoC 容器最頂級接口 BeanFactory 的時候, 可以看到 isSingleton 和 isPrototype 兩個方法。其中,isSingleton 方法如果返回 true,則 Bean 在 loC 容器中以單例存在,這也是 Spring IoC 容器的默認值;如果 isPrototype 方法返回 true,則當我們每次獲取 Bean 的時候, IoC 容器都會創(chuàng)建一個新的 Bean,這顯然存在很大的不同,這便是Spring Bean 的作用域的問題。在一般的容器中, Bean都會存在單例(Singleton)和原型(Prototype)兩種作用域, Java EE 廣泛地使用在互聯(lián)網(wǎng)中,而在 Web容器中, 則存在頁面(page)、請求(request)、會話 (session)和應用(application) 4 種作用域對于頁面(page),是針對 JSP 當前頁面的作用域,所以 Spring是無法支持的。為了滿足各類的作用域,在Spring 的作用域中就存在如表所示的幾種類型。

作用域類型 使用范圍 作用域描述
singleton 所有Spring 應用 默認值, loC 容器只存在單例
prototype 所有Spring 應用 每當從IoC 容器中取出一個 Bean,則創(chuàng)建一個新的Bean
session Spring Web 應用 HTTP 會話
application Spring Web 應用 Web 工程生命周期
request Spring Web 應用 Web 工程單次請求 (request)
globalSession Spring Web 應用 在一個全局的HTTPSession 中, 一個 Bean 定義對應一個實例。 實踐中基本不使用
  • 前四個最常用
  • 對于application作用域,完全可以使用單例來替代。

下面我們探討單例 (Singleton)和原型(prototype)的區(qū)別

首先定義一個類

@Component 
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
public class ScopeBean { }

這是一個簡單的類, 可以看到這里聲明作用域的代碼已經(jīng)被注釋掉了, 這樣就是啟用默認的作用域,實際就是單例。為了證明作用域的存在,我們進行一下測試:

AnnotationConfigApplicationContext ctx
				=new AnnotationConfigApplicationContext (AppConfig.class);
		ScopeBean scopeBeanl = ctx.getBean (ScopeBean.class);
		ScopeBean scopeBean2 = ctx.getBean (ScopeBean .class);
		System.out.println (scopeBeanl == scopeBean2) ;

SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC
從測試的結果來看,顯然scopeBeanl 和 scopeBean2 這兩個變量都指向了同一的實例,所以在IoC容器中, 只有一個ScopeBean 的實例。 然后取消代碼中作用域代碼的注釋,進行同樣的測試, 則可以看到scopeBeanl == scopeBean2 返回的將是 false,而不再是 true, 那是因為我們將Bean 的作用域修改為了 prototype,這樣就能讓IoC 容器在每次獲取Bean 時,都新建一個Bean的實例返回給調用者。
SpringBoot:詳解Bean生命周期和作用域,# 深入淺出SpringBoot,spring boot,后端,java,軟件工程,Bean,IOC
這里的 ConfigurableBeanFactory 只能提供單例 ( SCOPE_ SINGLETON )和原型 ( SCOPE_PROTOTYPE)兩種作用域供選擇, 如果是在 SpringMVC環(huán)境中,還可以使用 WebApplicationContext去定義其他作用域, 如請求(SCOPE REQUEST)、 會話 (SCOPE_SESSION) 和應用 (SCOPE_APPLICATION)。 例如,下面的代碼就是定義請求作用域:

@Component 
@Scope(WebApplicationContext.SCOPE_REQUEST) 
public class ScopeBean { }

總結

以上就是Bean生命周期和作用域的講解。文章來源地址http://www.zghlxwxcb.cn/news/detail-811639.html

到了這里,關于SpringBoot:詳解Bean生命周期和作用域的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Bean的作用域和生命周期

    Bean的作用域和生命周期

    目錄 1.作?域定義 1.1Bean的6個作用域 1.singleton:單例作用域 2.prototype:多例作用域 3.request:請求作用域 4.session:會話作用域 5.application:全局作用域 6.websocket:HTTP WebSocket作用域 單例作?域(singleton) VS 全局作?域(application) 1.2設置作用域 1.直接設置值@Scope(\\\"potptype\\\") 2.用枚舉設置:@Scop

    2024年02月02日
    瀏覽(25)
  • Spring Bean作用域與生命周期

    Spring Bean作用域與生命周期

    目錄 Bean的作用域: Bean有六大行為模式 1、singleton:單例模式(默認) 2、prototype: 原型模式(多例模式) 3、request: 請求作用域(Spring MVC) 4、session: 會話作用域(Spring MVC) 5、application: 全局作用域(Spring MVC) 6、websocket: HTTP WebSocket 作用域(Spring WebSocket) applicationContext和singleton的區(qū)別? Bea

    2024年02月02日
    瀏覽(24)
  • Spring | Bean 作用域和生命周期

    Spring | Bean 作用域和生命周期

    Spring 是用來讀取和存儲 Bean,因此在 Spring 中 Bean 是最核心的操作資源,所以接下來我們深入學習?下 Bean 對象 假設現(xiàn)在有?個公共的 Bean,提供給 A 用戶和 B 用戶使用,然而在使用的途中 A 用戶卻 “悄悄” 地修改了公共 Bean 的數(shù)據(jù),導致 B 用戶在使用時發(fā)生了預期之外的邏

    2024年02月14日
    瀏覽(19)
  • Spring(Bean 作用域和生命周期)

    Spring(Bean 作用域和生命周期)

    目錄 1. 案例1: Bean作用域的問題 2. 作用域 3. 設置 Bean 的作用域 4. Spring 的執(zhí)行流程 5. Bean 的生命周期 現(xiàn)在有一個公共的 Bean,通過給 A 用戶 和 B 用戶使用, 然后在使用的過程中 A 偷偷的修改了公共 Bean 的數(shù)據(jù), 導致 B 在使用時發(fā)生了預期之外的邏輯錯誤 (1) 公共 Bean:? ?[名稱是

    2024年02月19日
    瀏覽(78)
  • 【Spring】Bean的作用域與生命周期詳情:請簡述Spring的執(zhí)行流程并分析Bean的生命周期?

    【Spring】Bean的作用域與生命周期詳情:請簡述Spring的執(zhí)行流程并分析Bean的生命周期?

    ?我們都知道,Spring框架為開發(fā)人員提供了很多便捷,這使得開發(fā)人員能夠更加專注于應用程序的核心業(yè)務邏輯,而不需要花費大量時間和精力在技術細節(jié)上。作為一個包含眾多工具方法的IoC容器,存取JavaBean是其極為重要的一個環(huán)節(jié)。本文就對Spring中的Bean的作用域和生命周

    2024年02月12日
    瀏覽(27)
  • 【Spring】Bean的作用域和生命周期

    【Spring】Bean的作用域和生命周期

    目錄 一、引入案例來探討B(tài)ean的作用域 二、Bean的作用域 2.1、Bean的6種作用域 2.2、設置Bean的作用域 三、Spring的執(zhí)行流程 ?四、Bean的聲明周期 1、生命周期演示 首先我們創(chuàng)建一個User類,定義一個用戶信息,在定義一個Users類,使用方法注解將user存入Spring中,然后兩個用戶A對這

    2024年02月14日
    瀏覽(24)
  • Spring Bean的作用域及生命周期

    Spring Bean的作用域及生命周期

    目錄 前言: Bean的作用域(Scope) 單例模式 原型模式(多例作用域) 請求作用域(request) 會話作用域 全局作用域 網(wǎng)絡長連接 Spring執(zhí)行流程 Bean的生命周期 測試 小結: ? ? 使用Spring框架時,我們需要清楚Spring托管Bean的作用域和生命周期,這樣使用框架才會更加得心應手。

    2024年02月03日
    瀏覽(22)
  • 【JavaEE進階】Bean 作用域和生命周期

    【JavaEE進階】Bean 作用域和生命周期

    注意在此例子中需要用到lombok lombok是什么? Lombok 是一個 Java 庫,它通過注解的方式來簡化 Java 代碼的編寫。它提供了一組注解,讓我們可以通過在代碼中添加這些注解來自動生成樣板式的代碼,如 getter、setter、構造函數(shù)、toString 等。 使用 Lombok 可以有效地減少冗余的樣板代

    2024年02月12日
    瀏覽(25)
  • Spring Bean的作用域和生命周期

    Spring Bean的作用域和生命周期

    Bean 的作用域指的是 Bean 在 Spring 容器中的行為(Bean 實例創(chuàng)建及生命周期),它的行為是由 Spring 來管理的,可以根據(jù)具體情況選擇不同的作用域來達到性能優(yōu)化、資源利用最大化和可維護性等目的。 Bean 作用域(Scope)類型主要有如下幾種: 其中前兩種是 Spring 核心作用域,

    2024年02月12日
    瀏覽(28)
  • Bean 作用域、生命周期和Spring執(zhí)行流程

    Bean 作用域、生命周期和Spring執(zhí)行流程

    假設現(xiàn)在有?個公共的 Bean,提供給 A ?戶和 B ?戶使?,然?在使?的途中 A ?戶卻“悄悄”地修改了公共 Bean 的數(shù)據(jù),導致 B ?戶在使?時發(fā)?了預期之外的邏輯錯誤。 我們可以看到,B 用戶在使用這個Bean對象時,得到的Dog是被A 用戶修改過的,這無疑會給 B 用戶帶來很

    2024年02月12日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包