Spring中Bean的生命周期詳解

目錄

  1. Bean的定義和作用
  2. Bean的生命周期概述
  3. Bean實例化階段
  4. 依賴注入階段
  5. 初始化階段
  6. Bean的使用
  7. 銷毀階段
  8. 完整的Bean生命周期流程
  9. 示例代碼
  10. 總結

Bean的定義和作用

在Spring框架中,Bean是指由Spring IoC容器管理的Java對象。Bean是構建Spring應用程序的基本單元,幾乎所有的Java對象都可以被定義為Bean來交由容器管理。Bean的主要作用包括以下幾點:

  1. 解耦合:通過依賴注入(Dependency Injection,DI),使得對象之間的依賴關系不再直接管理,減少代碼耦合。
  2. 生命周期管理:Spring容器負責管理Bean的創建、初始化、使用和銷毀等全過程。
  3. 配置簡化:通過配置文件(如XML或注解)來管理對象的創建和依賴關系,減少硬編碼。
  4. 統一管理:容器統一管理Bean的實例數量和作用范圍(Scope),節省資源。

Bean的生命周期概述

Bean的生命周期可以分為以下幾個主要階段:

  1. 實例化階段:通過構造函數或工廠方法創建Bean實例。
  2. 依賴注入階段:將所需的依賴注入到Bean中。
  3. 自定義初始化階段:執行自定義的初始化方法來進行額外的Bean設置。
  4. Bean的使用:Bean處于活躍狀態,并由外部應用程序調用使用。
  5. 銷毀階段:在容器關閉時,執行銷毀方法,進行資源清理。

下面我們將詳細探討每個階段的具體內容和機制。

Bean實例化階段

Bean實例化是Bean生命周期的開始。在實例化階段,Spring容器通過以下幾種方式創建Bean實例:

  1. 構造函數:默認情況下,Spring會通過無參構造函數創建Bean實例。如果沒有無參構造函數,可以通過@Configuration和@Bean注解來顯式指定構造函數。
  2. 靜態工廠方法:使用靜態工廠方法創建Bean實例,需要在配置文件中指定工廠方法名。
  3. 實例工廠方法:使用實例工廠方法創建Bean實例,需要先提供一個工廠實例,再調用工廠實例方法創建Bean。

示例代碼如下:

// 通過構造函數創建Bean
@Component
public class ExampleBean {public ExampleBean() {System.out.println("ExampleBean實例化!");}
}// 通過靜態工廠方法創建Bean
public class StaticFactory {public static ExampleBean createInstance() {return new ExampleBean();}
}// 通過實例工廠方法創建Bean
public class InstanceFactory {public ExampleBean createInstance() {return new ExampleBean();}
}

在配置文件中配置靜態工廠方法和實例工廠方法:

<bean id="exampleBeanStatic" class="com.example.StaticFactory" factory-method="createInstance"/>
<bean id="exampleBeanInstance" factory-bean="instanceFactory" factory-method="createInstance"/>
<bean id="instanceFactory" class="com.example.InstanceFactory"/>

依賴注入階段

在實例化階段完成后,容器會自動進行依賴注入。依賴注入有以下幾種方式:

  1. 構造函數注入:通過構造函數參數注入依賴對象。
  2. Setter方法注入:通過Setter方法注入依賴對象。
  3. 字段注入:直接通過反射注入依賴對象(需要使用注解)。

構造函數注入

構造函數注入通過構造函數參數傳遞依賴對象:

@Component
public class ExampleService {private final ExampleRepository repository;@Autowiredpublic ExampleService(ExampleRepository repository) {this.repository = repository;}
}

Setter方法注入

Setter方法注入通過Setter方法來注入依賴對象:

@Component
public class ExampleService {private ExampleRepository repository;@Autowiredpublic void setRepository(ExampleRepository repository) {this.repository = repository;}
}

字段注入

字段注入通過直接在字段上使用@Autowired注解:

@Component
public class ExampleService {@Autowiredprivate ExampleRepository repository;
}

初始化階段

在依賴注入完成后,Bean會進入初始化階段。初始化階段旨在完成Bean實例的進一步配置和準備工作。Spring提供了幾種方式來定制Bean的初始化行為:

  1. 實現InitializingBean接口:通過實現afterPropertiesSet方法來定義自定義初始化邏輯。
  2. 使用@PostConstruct注解:通過在方法上使用@PostConstruct注解來定義初始化邏輯。
  3. 自定義初始化方法:在XML配置文件或注解中指定自定義的初始化方法。

實現InitializingBean接口

實現InitializingBean接口并重寫afterPropertiesSet方法:

@Component
public class ExampleBean implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("ExampleBean初始化!");}
}

使用@PostConstruct注解

在方法上使用@PostConstruct注解:

@Component
public class ExampleBean {@PostConstructpublic void init() {System.out.println("ExampleBean初始化!");}
}

自定義初始化方法

在配置文件或注解中指定初始化方法:

<bean id="exampleBean" class="com.example.ExampleBean" init-method="init"/>

或者通過@Bean注解:

@Configuration
public class AppConfig {@Bean(initMethod = "init")public ExampleBean exampleBean() {return new ExampleBean();}
}

Bean的使用

初始化完成后,Bean進入使用階段。此時,Bean處于活躍狀態,可以被其他對象或外部應用程序調用使用。在使用過程中,Bean可能會隨著業務邏輯的需要進行多次方法調用或狀態變更。

示例使用

@Component
public class ServiceConsumer {@Autowiredprivate ExampleService exampleService;public void performAction() {exampleService.doSomething();}
}

銷毀階段

當Bean的生命周期結束時,容器會執行銷毀方法,釋放資源。Spring提供了幾種方式來定制Bean的銷毀行為:

  1. 實現DisposableBean接口:通過實現destroy方法來定義自定義銷毀邏輯。
  2. 使用@PreDestroy注解:通過在方法上使用@PreDestroy注解來定義銷毀邏輯。
  3. 自定義銷毀方法:在XML配置文件或注解中指定自定義的銷毀方法。

實現DisposableBean接口

實現DisposableBean接口并重寫destroy方法:

@Component
public class ExampleBean implements DisposableBean {@Overridepublic void destroy() throws Exception {System.out.println("ExampleBean銷毀!");}
}

使用@PreDestroy注解

在方法上使用@PreDestroy注解:

@Component
public class ExampleBean {@PreDestroypublic void cleanup() {System.out.println("ExampleBean銷毀!");}
}

自定義銷毀方法

在配置文件或注解中指定銷毀方法:

<bean id="exampleBean" class="com.example.ExampleBean" destroy-method="cleanup"/>

或者通過@Bean注解:

@Configuration
public class AppConfig {@Bean(destroyMethod = "cleanup")public ExampleBean exampleBean() {return new ExampleBean();}
}

完整的Bean生命周期流程

通過上述各個階段的介紹,我們可以總結出Spring中Bean生命周期的完整流程:

  1. 實例化:通過構造函數或工廠方法創建Bean實例。
  2. 依賴注入:將依賴對象注入到Bean中。
  3. BeanPostProcessorpostProcessBeforeInitialization方法:在初始化之前執行。
  4. 初始化:執行自定義的初始化方法。
  5. BeanPostProcessorpostProcessAfterInitialization方法:在初始化之后執行。
  6. Bean的使用:Bean處于活躍狀態,供外部調用使用。
  7. 銷毀:容器關閉時,執行銷毀方法,進行資源清理。

示例代碼

讓我們通過一個完整的示例來展示Spring中Bean的生命周期各個步驟。假設我們有一個簡單的業務服務類ExampleService

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class ExampleService implements InitializingBean, DisposableBean {private ExampleRepository repository;@Autowiredpublic ExampleService(ExampleRepository repository) {this.repository = repository;}@PostConstructpublic void postConstruct() {System.out.println("ExampleService的postConstruct初始化!");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("ExampleService的afterPropertiesSet初始化!");}public void doSomething() {System.out.println("ExampleService在執行業務邏輯!");}@PreDestroypublic void preDestroy() {System.out.println("ExampleService的preDestroy銷毀!");}@Overridepublic void destroy() throws Exception {System.out.println("ExampleService的destroy銷毀!");}
}

配置類中定義Bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "cleanup")public ExampleBean exampleBean() {return new ExampleBean();}
}

應用程序主類:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MainApplication {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);ExampleService exampleService = context.getBean(ExampleService.class);exampleService.doSomething();context.close();}
}

在運行上述代碼后,我們會在控制臺中看到Bean的各個生命周期階段的相關輸出:

ExampleService的postConstruct初始化!
ExampleService的afterPropertiesSet初始化!
ExampleService在執行業務邏輯!
ExampleService的preDestroy銷毀!
ExampleService的destroy銷毀!

總結

理解Spring中Bean的生命周期是掌握Spring框架基礎的重要環節。通過本文的詳細介紹,我們從實例化、依賴注入、初始化、使用和銷毀五個階段全方位解析了Bean的生命周期,并通過示例代碼展示了如何在實際開發中應用這些知識。希望本文能幫助您更好地理解和使用Spring框架,以構建更加高效、易維護的Java應用程序。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20740.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20740.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20740.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

word避免畫質畫質模糊方法

問題描述&#xff1a; ??近期寫文檔時會高頻率貼圖&#xff0c;粘圖過程中發現Word會自動壓縮圖片畫質&#xff0c;而且壓縮得很嚴重&#xff0c;下面是一幅圖被壓縮前后的畫質對比 &#xff08;圖片壓縮前&#xff09; &#xff08;圖片壓縮后&#xff09; 解決方案&#x…

基于JSP的九宮格日志網站

你好呀&#xff0c;我是學長貓哥&#xff01;如果有需求可以文末加我。 開發語言&#xff1a;Java 數據庫&#xff1a;MySQL 技術&#xff1a;JSP技術 工具&#xff1a;瀏覽器/服務器&#xff08;B/S&#xff09;結構 系統展示 首頁 管理員功能模塊 用戶功能模塊 摘要 本…

GPT-4o VS GPT-3.5 完勝

前言&#xff1a; 最近&#xff0c;GPT-4o已經限時免費開放了&#xff0c;試了一下&#xff0c;然后&#xff0c;說我的時間到了&#xff0c;然后&#xff0c;有給我轉到3.5&#xff0c;正好遇到一個問題做一下對吧&#xff0c;感覺4O完勝啊。3.5還是很好胡謅&#xff0c;也就…

[Algorithm][動態規劃][子序列問題][最長定差子序列][最長的斐波那契子序列的長度]詳細講解

目錄 1.最長定差子序列1.題目鏈接2.算法原理詳解3.代碼實現 2.最長的斐波那契子序列的長度1.題目鏈接2.算法原理詳解3.代碼實現 1.最長定差子序列 1.題目鏈接 最長定差子序列 2.算法原理詳解 思路&#xff1a; 確定狀態表示 -> dp[i]的含義 以i位置元素為結尾的所有子序列…

Python知識點3---條件判斷語句

提前說一點&#xff1a;如果你是專注于Python開發&#xff0c;那么本系列知識點只是帶你入個門再詳細的開發點就要去看其他資料了&#xff0c;而如果你和作者一樣只是操作其他技術的Python API那就足夠了。 Python的條件判斷語句和其他的語言有些不一樣&#xff0c;它只有if語…

【從加載數據庫驅動包,理解java SPI】

SPI&#xff08;Service Provider Interface&#xff09; 從1.6引入&#xff0c;基于ClassLoader 來加載并發現服務的機制 對于msyql驅動 引入依賴 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><v…

11.2 選擇排序

目錄 11.2 選擇排序 11.2.1 算法特性 11.2 選擇排序 選擇排序&#xff08;selection sort&#xff09;的工作原理非常簡單&#xff1a;開啟一個循環&#xff0c;每輪從未排序區間選擇最小的元素&#xff0c;將其放到已排序區間的末尾。 設數組的長度為 &#x1d45b;…

華東師范大學研究團隊《Ecology Letters 》揭示植物如何改變其物候以響應全球變化

自工業革命以來&#xff0c;人類活動導致多種環境因子同時發生變化&#xff0c;包括氣候變暖、降水模式改變、氮沉降增加和大氣CO2升高。這些變化預計會影響植物生命周期事件的季節時序—植物物候&#xff08;Nature Reviews Earth & Environment | 傅伯杰院士團隊發文闡述…

[C][棧幀]詳細講解

目錄 1.棧幀1.進程地址空間2.棧幀說明 2.認識相關寄存器3.認識相關匯編命令4.過程理解5.棧幀總結6.補充 1.棧幀 1.進程地址空間 .進程地址空間 2.棧幀說明 調用函數&#xff0c;形成棧幀函數返回&#xff0c;釋放棧幀局部變量是存放在棧區上的棧區內存的使用習慣是&#xff…

BPTT算法詳解:深入探究循環神經網絡(RNN)中的梯度計算【原理理解】

引言 在深度學習領域中&#xff0c;我們經常處理的是獨立同分布&#xff08;i.i.d&#xff09;的數據&#xff0c;比如圖像分類、文本生成等任務&#xff0c;其中每個樣本之間相互獨立。然而&#xff0c;在現實生活中&#xff0c;許多數據具有時序結構&#xff0c;例如語言模型…

什么是PLAB?

接上文PLAB---》 可以看到和TLAB很像&#xff0c;PLAB即 Promotion Local Allocation Buffers。用在年輕代對象晉升到老年代時。 在多線程并行執行YGC時&#xff0c;可能有很多對象需要晉升到老年代&#xff0c;此時老年代的指針就"熱"起來了&#xff0c;于是搞了個…

Google Cloudbuild yaml file 中 entrypoint 和 args 的寫法

編寫cloudbuild.yaml 時有幾個關鍵參數 entrypoint 和 args 的基本介紹 id: 顯示在 cloud build logs 里的item 名字 name: docker 鏡像名字 - 下面的命令會在這個鏡像的1個容器instance 內執行 entrypoint: 執行的命令入口 &#xff0c; 只能有1個對象 args&#xff1a; 命名…

函數的創建和調用

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 提到函數&#xff0c;大家會想到數學函數吧&#xff0c;函數是數學最重要的一個模塊&#xff0c;貫穿整個數學學習過程。在Python中&#xff0c;函數…

深入解析 YOLOv8 中的 `conv.py`(代碼圖文全解析-下)

&#x1f60e; 作者介紹&#xff1a;我是程序員行者孫&#xff0c;一個熱愛分享技術的制能工人。計算機本碩&#xff0c;人工制能研究生。公眾號&#xff1a;AI Sun&#xff0c;視頻號&#xff1a;AI-行者Sun &#x1f388; 本文專欄&#xff1a;本文收錄于《yolov8》系列專欄&…

【linux軟件基礎知識】與調度相關的進程描述符

進程描述符 每個進程描述符都包括幾個與調度相關的字段,如下代碼所示: //include/asm-arm/thread_info.h /** low level task data that entry.S needs immediate access to.* __switch_to() assumes cpu_context follows immediately after cpu_domain.*/ struct thread_in…

vite為什么速度快

原因 vite快的原因是因為 vite在開發環境中是使用的 esbuild&#xff0c;esbuild 是 go 寫的&#xff0c;go 編譯型語言、多線程&#xff0c;nodejs 解釋型語言、單線程&#xff0c;并且 vite 使用了原生 esm 導入的&#xff0c;所以快一點&#xff0c;當然&#xff0c;這也…

6.1Java方法

1、方法定義&#xff1a; 方法是一種語法結構&#xff0c;它可以把一段代碼封裝成一個功能&#xff0c;以便重復調用 方法的完整格式&#xff1a; 修飾符 返回類型 方法名(形參列表){ 方法體代碼(需要執行的功能代碼) return 返回值; } package com.define;public class …

【緩存】框架層常見問題和對策

緩存是為了加快讀寫速度&#xff0c;再了解redis這類框架層的緩存應用之前&#xff0c;我們不妨先思考下操作系統層面的緩存解決方案&#xff0c;這樣有助于我們更深的理解緩存&#xff0c;哪些是系統層面的&#xff0c;哪些是服務層面。 以下是一些常見的緩存問題及其解決方案…

面向對象編程 (OOP):深入理解繼承、多態和抽象

1. 簡介 面向對象編程 (OOP) 是一種強大的編程范式&#xff0c;它通過將程序組織成對象的集合來簡化軟件設計和開發。與傳統的程序設計方法相比&#xff0c;OOP 提供了一種更自然、更易于理解和維護的方式來構建復雜的軟件系統。OOP 的核心概念包括&#xff1a;對象、類、繼承、…

Java進階學習筆記31——日期時間

Date&#xff1a; 代表的是日期和時間。 分配Date對象并初始化它以表示自標準基準時間&#xff08;稱為紀元&#xff09;以來的指定毫秒數&#xff0c;即1970年1月1日00:00:00。 有參構造器。 package cn.ensource.d3_time;import java.util.Date;public class Test1Date {pu…