首頁 > 軟體

Spring Bean作用域與生命週期深入講解

2022-07-18 18:04:53

1.作用域定義

限定程式中變數的可用範圍叫做作用域,或者說在原始碼中定義變數的某個區域就叫做作用域。

Bean 的作用域

而 Bean 的作用域是指 Bean 在 Spring 整個框架中的某種行為模式,比如 singleton 單例作用域,就表示 Bean 在整個 Spring 中只有一份,它是全域性共用的,那麼當其他人修改了這個值之後,那麼另一個人讀取到的就是被修改的值。

Bean 的 6 種作用域

Spring 容器在初始化一個 Bean 的範例時,同時會指定該範例的作用域。Spring有 6 種作用域,最後四種是基於 Spring MVC 生效的:

  • singleton:單例作用域(預設作用域)
  • prototype:原型作用域(多例作用域)
  • request:請求作用域
  • session:回話作用域
  • application:全域性作用域
  • websocket:HTTP WebSocket 作用域

注意後 4 種狀態是 Spring MVC 中的值,在普通的 Spring 專案中只有前兩種。

1,2為Spring普通專案(Spring Core) 3,4,5為Spring MVC 6屬於Spring WebSocket

singleton

  • 官方說明:(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
  • 描述:該作用域下的Bean在IoC容器中只存在一個範例:獲取Bean(即通過applicationContext.getBean等方法獲取)及裝配Bean(即通過@Autowired注入)都是同一個物件。
  • 場景:通常無狀態的Bean使用該作用域。無狀態表示Bean物件的屬性狀態不需要更新
  • 備註:Spring預設選擇該作用域

prototype

  • 官方說明:Scopes a single bean definition to any number of object instances.
  • 描述:每次對該作用域下的Bean的請求都會建立新的範例:獲取Bean(即通過applicationContext.getBean等方法獲取)及裝配Bean(即通過@Autowired注入)都是新的物件範例。
  • 場景:通常有狀態的Bean使用該作用域

request

  • 官方說明:Scopes a single bean definition to the lifecycle of a single HTTP request. Thatis, each HTTP request has its own instance of a bean created off the back of a singlebean definition. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:每次http請求會建立新的Bean範例,類似於prototype
  • 場景:一次http的請求和響應的共用Bean
  • 備註:限定SpringMVC中使用

session

  • 官方 說明:Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一個http session中,定義一個Bean範例
  • 場景: 使用者回話的共用Bean, 如:記錄 一個使用者的登陸資訊
  • 備註:限定SpringMVC中使用

application(瞭解)

  • 官方說明:Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一個http servlet Context中,定義一個Bean範例
  • 場景:Web應 的上下 資訊, 如:記錄一個應用的共用資訊
  • 備註:限定SpringMVC中使用

websocket(瞭解)

  • 官方說明:Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一個HTTP WebSocket的 命週期中,定義一個Bean範例
  • 場景:WebSocket的每次對談中,儲存了一個Map結構的頭資訊,將用來包裹使用者端訊息頭。第一次初始化後,直到WebSocket結束都是同一個Bean。
  • 備註:限定Spring WebSocket中使用

單例作用域(singleton)和全域性作用域(application)區別

singleton 是 Spring Core 的作用域;

application 是 Spring Web 中的作用域;

singleton 作 於 IoC 的容器, application 作 於 Servlet 容器。

2.設定作用域

使用@Scope標籤就可以宣告Bean的作用域,比如設定Bean的作用域

@Scope標籤可以修飾方法,也可以修飾類,@Scope有兩種設定方式:

1.直接設定值:@Scope("prototype")

2.直接列舉設定:@Scope("ConfigurableBeanFactory.SCOPE_PROTOTYPE")

3.Bean 原理分析

3.1 Bean(Spring)執行流程

Bean 執行 流程(Spring 執 流程):啟動 Spring 容器 -> 範例化 Bean(分配記憶體空間,從 到有) -> Bean 註冊到 Spring 中(存操作) -> 將 Bean 裝配到需要的類中(取操作)。

3.2 Bean生命週期

所謂的生命週期指的是一個物件從誕生到銷燬的整個生命過程,我們把這個過程就叫做一個物件的生命週期。

Bean 的生命週期分為以下 5 部分:

範例化 Bean(為 Bean 分配記憶體空間)【範例化!=初始化;只是執行分配記憶體空間的功能】

設定屬性(Bean 注入和裝配)【執行依賴類的注入A需要使用B的方法,先初始化並將B載入到當前類】

Bean 初始化

  • 實現了各種Aware 通知的方法,如BeanNameAware、BeanFactoryAware、ApplicationContextAware 的介面方法;
  • 執行BeanPostProcessor 初始化前置方法;
  • 執行@PostConstruct初始化方法,依賴注入操作之後被執行;
  • 執行指定的 init-method方法(如果有指定的話);
  • 執行BeanPostProcessor 初始化後置方法。

使用Bean

銷燬 Bean

銷燬容器的各種 法,如 @PreDestroy、DisposableBean 介面方法、destroy-method。

執行流程如下圖所示:

範例化和初始化的區別

範例化和屬性設定是 Java 級別的系統“事件”,其操作過程不可人工干預和修改;而初始化是給開發者提供的,可以在範例化之後,類載入完成之前進行自定義“事件”處理。

生命流程的“故事”

Bean 的生命流程看似繁瑣,但咱們可以以生活中的場景來理解它,比如我們現在需要買一棟房子,那麼我們的流程是這樣的:

  • 先買房(範例化,從無到有);
  • 裝修(設定屬性);
  • 買家電,如洗衣機、冰箱、電視、空調等([各種]初始化);
  • 入住(使用 Bean);
  • 賣出去(Bean 銷燬)。

生命週期演示:

package com.beans;
import org.springframework.beans.factory.BeanNameAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class BeanLifeComponent implements BeanNameAware {
    @PostConstruct
    public void postConstruct() {
        System.out.println("執行 PostConstruct()");
    }
    public void init() {
        System.out.println("執行 BeanLifeComponent init-method");
    }
    public void destory() {
        System.out.println("執行了 destory 方法");
    }
    @PreDestroy
    public void preDestroy() {
        System.out.println("執行:preDestroy()");
    }
    public void setBeanName(String s) {
        System.out.println("執行了 setBeanName 方法:" + s);
    }
}

xml 設定如下:

<?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:content="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">
    <!-- 設定需要儲存到 spring 中的 bean 根目錄 -->
    <content:component-scan base-package="com.beans"></content:component-scan>
    <bean id="beanlife" class="com.beans.BeanLifeComponent"
          init-method="init" destroy-method="destory"></bean>
</beans>

呼叫類:

package com;
import com.beans.BeanLifeComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App2 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);
        System.out.println("執行銷燬方法");
        beanLifeComponent.destory(); // 執行銷燬方法
    }
}

步驟 2 和步驟 3 的順序不能打個顛倒!!!

到此這篇關於Spring Bean作用域與生命週期深入講解的文章就介紹到這了,更多相關Spring Bean作用域與生命週期內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com