技術面:Spring (bean的生命周期、創建方式、注入方式、作用域)

Spring Bean的生命周期是什么樣的?

在Spring容器里一個Bean的從創建到銷毀一般都是經歷了以下幾個階段:
定義階段(Bean元信息配置)=>實例化階段(創建Bean對象)=>初始化階段(執行初始化邏輯)=>使用階段(Bean可用)=>銷毀階段(釋放資源)
Spring bean的生命周期

定義階段(BeanDefinition解析)

Spring通過配置(XML、注解、Java配置)解析Bean的元數據,生成BeanDefinition對象
BeanDefinition存儲了Bean的類名、作用域(scope)、依賴項(depends-on)、初始化方法、銷毀方法等元數據。
所有BeanDefinition存儲在容器的BeanDefinitionMap(一個HashMap)中,鍵為Bean名稱,值為BeanDefinition對象。
解析器:

  • XML配置:XmlBeanDefinitionReader解析<bean>標簽。
  • 注解配置:ClassPathBeanDefinitionScanner掃描@Component等注解。
  • Java配置:ConfigurationClassPostProcessor解析@Bean方法。

實例化階段(創建Bean實例)

根據BeanDefinition通過反射或工廠方法創建Bean實例(對象),但此時屬性未注入
默認通過無參構造方法實例化(若未指定,Spring會強制要求無參構造)。

AbstractAutowireCapableBeanFactory類中的createBeanInstance方法中實現。

屬性值填充(依賴注入)

為Bean的屬性設置值或注入依賴

  • 通過@Autowired@ValueXML<property>等方式注入屬性。
  • 若注入的依賴是其他Bean,會遞歸觸發依賴Bean的生命周期。
  • 循環依賴問題:在屬性注入階段處理循環依賴(通過三級緩存解決)。

AbstractAutowireCapableBeanFactorypopulateBean方法中處理。

Aware接口回調設置

若Bean實現了特定Aware接口,Spring會回調對應方法,注入容器相關對象

  • BeanNameAware:注入Bean在容器中的名稱(setBeanName(String beanName))。
  • BeanFactoryAware:注入當前Bean所在的BeanFactory(setBeanFactory(BeanFactory beanFactory))。
  • ApplicationContextAware:若容器是ApplicationContext,注入應用上下文(setApplicationContext(ApplicationContext applicationContext))。

AbstractAutowireCapableBeanFactoryinitializeBean方法中調用。

BeanPostProcessor前置處理

在Bean初始化前,允許自定義BeanPostProcessor對Bean實例進行處理。
主要是調用BeanPostProcessorpostProcessBeforeInitialization方法。
常見的實現類

  • ApplicationContextAwareProcessor:處理ApplicationContextAware接口。
  • InitDestroyAnnotationBeanPostProcessor:處理@PostConstruct注解。

AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsBeforeInitialization方法執行。

InitializingBean處理以及自定義init-method處理

執行Bean的初始化邏輯。
InitializingBean處理,在所有Bean屬性設置完成后進行初始化操作。如果Bean實現了InitializingBean接口,InitializingBeanafterPropertiesSet方法會被調用。

自定義init-method處理,如果Bean在配置文件中定義了初始化方法那么該方法會被調用。
例如:通過XML配置init-method或Java配置@Bean(initMethod=“xxx”)。

AbstractAutowireCapableBeanFactoryinvokeInitMethods方法中調用

BeanPostProcessor后置處理

在Bean初始化后,允許自定義BeanPostProcessor對Bean實例進行處理。
BeanPostProcessorpostProcessAfterInitialization方法會被調用。

常見用途:AOP代理(如AbstractAutoProxyCreator在此階段為目標對象創建代理)

AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsAfterInitialization方法執行

注冊DisposableBean回調

如果Bean實現了DisposableBean接口或在Bean定義中指定了自定義的銷毀方法,Spring容器會為這些Bean注冊一個銷毀回調,確保在容器關閉時能夠正確地清理資源。

AbstractAutowireCapableBeanFactory類中的registerDisposableBeanlfNecessary方法中實現

Bean使用階段

**Bean已完全初始化,可被應用程序使用。**通過依賴注入獲取Bean實例(如@AutowiredApplicationContext.getBean())。
此階段Bean處于“可用”狀態,直到容器關閉。

Bean銷毀階段

容器關閉時,釋放Bean資源。
主要步驟:

  • 接口回調:若Bean實現了DisposableBean,調用destroy方法。
  • 注解:若方法標注了@PreDestroy,Spring會調用該方法。
  • 自定義銷毀方法:通過XML配置destroy-method或Java配置@Bean(destroyMethod="xxx")
  • 資源釋放:如關閉數據庫連接、釋放文件句柄等。

DisposableBeanAdapterdestroy方法中實現

總結

通過代碼出處,可以觀察到整個Bean的創建的過程都依賴于AbstractAutowireCapableBeanFactory這個類,而銷毀主要依賴DisposableBeanAdapter這個類。
AbstractAutowireCapableBeanFactory 的入口處,doCreateBean的核心代碼如下,其中包含了實例化、設置屬性值、初始化Bean以及注冊銷毀回調的幾個核心方法。
這里就不貼代碼了,想更深入看細節的可以去看源碼。

Spring中創建Bean的方式有哪些?

基于注解的自動掃描

通過注解標記類,并配合組件掃描實現自動注冊。
常見的注解有
@Component, @Service, @Repository, @Controller(及其衍生注解)。

例如:當在類上添加@Component時,再在配置類或 XML 中啟用組件掃描(@ComponentScan<context:component-scan>)。這個類在服務啟動時會自動被掃描到,然后注入到Spring容器。

@Configuration
@ComponentScan("com.jimoer.service")
public class BeanConfig {}
@Service
public class UserService {public void hello() {System.out.println("Hello from UserService");}
}@Component
public class UserHandler {public void hello() {System.out.println("Hello from UserHandler");}
}@Repository
public class UserRepository {public void hello() {System.out.println("Hello from UserRepository");}
}@Controller
public class UserController {public void hello() {System.out.println("Hello from UserController");}
}

使用@Configuration與@Bean 注解

通過 @Configuration 標注的配置類,顯式定義 Bean 的創建邏輯。
適用于:需要精確控制 Bean 的初始化邏輯(如依賴其他 Bean 或復雜條件)。

@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserService();}
}

XML 配置文件

通過 xml 的方式來定義 Bean。
在SpringBoot 流行以前,這種方式挺多的, SpringBoot 流行起來之后,這么用的越來越少了。

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"<bean id="userService" class="com.jimoer.demo.UserServiceImpl"><property name="message" value="Hello Spring!" /></bean>
</beans>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService");

更適用于遺留項目或需要與非注解配置兼容的場景。

使用@Import注解

@Import注解的作用是快速導入某一個或多個類,使這些類能夠被Spring加載到IOC容器中進行管理。
讓類被Spring 的 IOC 容器管理,這不也是創建 Bean 么,因此,這種方式也可以算是創建Bean的一種方式。

@Import({UserServiceImpl.class})
@Configuration
public class UserBeanConfiguration {
}

自定義注解

通過自定義一種注解,然后在 Spring 應用啟動過程中,通過自定義的 BeanDefinitionRegistryPostProcessorBeanfactoryPostProcessor 來掃描配置的包路徑,識別出帶有自定義注解的類。
這些處理器解析注解中的屬性(如接口類、版本號、超時時間等),并基于這些信息創建 Spring的 BeanDefinition
例如:Dubbo框架使用的@DubboService注解

@DubboService("version=1.0.0")
public class UserServiceImpl implements UserFacadeService {}

動態注冊(運行時注冊)

在運行時通過 BeanDefinitionRegistry 動態注冊 Bean。

// 獲取 BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 定義 Bean 的元數據
GenericBeanDefinition userDefinition = new GenericBeanDefinition();
userDefinition.setBeanClass(UserService.class);// 注冊 Bean
beanFactory.registerBeanDefinition("userService", userDefinition);

適用于:根據運行時條件動態生成 Bean(如插件化系統、動態配置)。

Spring Bean的注入方式有哪些?

使用@Autowired注解

@Autowired注解是Spring框架提供的一個注解,支持多種方式自動將Spring的bean注入到其他Bean中。

字段注入
@Component
public class JimoerUserService {@Autowiredprivate UserRepository userRepository;
}
構造方法注入
@Component
public class JimoerUserService {private final UserRepository userRepository;// Spring 4.3+ 可省略 @Autowired(單構造器)@Autowiredpublic JimoerUserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
setter注入
@Component
public class JimoerUserService {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}

使用@Resource和@Inject注解

除了Spring提供的注解,JDK也提供了可以互相注入Bean的注解,有@Resource@Inject

@Component
public class JimoerUserService {@Resourceprivate UserRepository userRepository;
}@Component
public class JiomerUserService {@Injectprivate UserRepository userRepository;
}

使用XML配置注入

如何不使用注解注入,還可以使用XML文件的配置進行Bean的互相注入。

<bean id="userRepository" class="com.jimoer.UserRepository"/>
<!-- 構造方法注入 -->
<bean id="userService" class="com.jiomer.UserService"><constructor-arg ref="userRepository"/>
</bean>
<!-- 字段注入 -->
<bean id="jimoerUserService" class="com.jiomer.JimoerUserService"><property name="userRepository" ref="userRepository"/>
</bean>

構造方法自動注入

其實從 Spring 4.3 開始,除非一個類中聲明了至少兩個構造函數,否則不需要用 @Autowired 標注構造函數,這個構造函數也能直接注入 Bean。

@Component
public class JimoerUserService {private UserRepository userRepository;public JimoerUserService(UserRepository userRepository){this.userRepository=userRepository;}
}

Spring Bean的作用域有哪些?

Spring的Bean的作用域,就是指這個Bean在哪個范圍內可以被使用。
不同的作用域決定了Bean的創建管理和銷毀的方式。

常見的作用域有SingletonPrototypeRequestSessionApplication這五種。
在代碼中,可以在定義一個Bean的時候,通過@Scope 注解來指定他的作用域。

如果沒有指定Bean的作用域,默認是Singleton(單例)。

Singleton(單例)

  • 周期:Spring 容器啟動時創建實例,容器關閉時銷毀。
  • 作用域:每個Spring IOC容器,只創建一個Bean實例。
  • 適用于:無狀態服務(如工具類、緩存管理器、數據庫連接池)。
  • 線程安全:需注意,若 Bean 有可變狀態(即Bean中存在線程共享變量),需通過同步機制或線程安全集合處理。
  • 配置方式:
@Component // 默認即為 singleton
public class SingletonBean {
}

Propertype(原型)

  • 周期:每次調用 getBean() 或注入時創建新實例,容器不負責銷毀。
  • 適用于:有狀態 Bean(如用戶會話數據、臨時對象)。
  • 線程安全:實例獨立,避免線程安全問題。
  • 配置方式:
@Component
@Scope("prototype")
public class PrototypeBean {
}

Request(HTTP 請求)

  • 周期:每個 HTTP 請求創建一個實例,請求結束后銷毀。
  • 適用于:Web 應用中請求級別的數據共享(如請求日志、上下文信息)。

僅適用于 Web 應用環境。

  • 配置方式:
@Component
@Scope("request")
public class RequestBean {
}

Session(HTTP 會話)

  • 周期:每個用戶會話(HttpSession)創建一個實例,會話結束時銷毀。
  • 適用于:用戶會話數據(如購物車、用戶偏好設置)。

僅適用于 Web 應用環境。

  • 配置方式:
@Component
@Scope("session")
public class SessionBean {
}

Application(應用)

  • 周期:Web 應用啟動時創建實例,應用關閉時銷毀。
  • 適用于:全局配置或共享資源(如應用級緩存、配置信息)。類似 singleton,但綁定到 ServletContext

僅適用于 Web 環境

  • 配置方式:
@Component
@Scope("application")
public class ApplicationBean {
}

Websocket(WebSocket 會話)

  • 周期:WebSocket 連接建立時創建實例,連接關閉時銷毀。
  • 適用于:WebSocket 會話上下文數據(如實時通信狀態)。

僅適用于 WebSocket 應用。

  • 配置方式:
@Component
@Scope("websocket")
public class WebSocketBean {
}

自定義作用域

一般情況下,在開發過程中,都是使用Singleton作用域,有時候也會用Propertype,其他幾個用的都不多。但是除了上面列舉的6個Spring提供作用域以外,還可以自己定義Bean作用域。

自定義一個Spring Bean的作用域,需要實現org.springframework.beans.factory.config.Scope接口,主要是實現如下幾個方法來管理Bean的生命周期。

package org.springframework.beans.factory.config;import org.springframework.beans.factory.ObjectFactory;public interface Scope {Object get(String var1, ObjectFactory<?> var2);Object remove(String var1);void registerDestructionCallback(String var1, Runnable var2);Object resolveContextualObject(String var1);String getConversationId();
}

自定義一個類,然后實現Scope接口,來實現我們自己的Bean作用域。

public class JimoerScope implements Scope{@Overridepublic Object get(String s, ObjectFactory<?> objectFactory) {// 獲取Bean的邏輯return objectFactory.getObject();}@Overridepublic Object remove(String s) {// 移除Bean的邏輯return null;}@Overridepublic void registerDestructionCallback(String s, Runnable runnable) {// 注冊Bean銷毀時的回調}@Overridepublic Object resolveContextualObject(String s) {// 解析上下文return null;}@Overridepublic String getConversationId() {// 獲取會話IDreturn "";}
}

接下來,我們將Spring配置中注冊這個自定義的作用域。
這可以通過ConfigurableBeanFactory.registerScope 方法實現。

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic JimoerScope jimoerScope(ConfigurableBeanFactory beanFactory) {JimoerScope jimoerScope = new JimoerScope();beanFactory.registerScope("jimoer", jimoerScope);return jimoerScope;}}

此時在Bean定義中使用自定義的作用域的名稱jimoer
Spring 容器將會根據你的自定義邏輯來創建和管理這些 Bean。

@Component
@Scope("jimoer")
public class CustomerScopeTest {
}

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

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

相關文章

SpringSecurity的應用

官方文檔 一、核心能力 1.1 身份認證 (Authentication) - “你是誰&#xff1f;” 多種認證方式&#xff1a;支持幾乎所有主流認證方案&#xff0c;如表單登錄&#xff08;Username/Password&#xff09;、HTTP Basic、HTTP Digest、OAuth 2.0、OIDC (OpenID Connect)、SAML …

跨境云手機與傳統手機的不同之處

傳統手機主要滿足個人日常生活中的通訊、娛樂、辦公等基礎需求&#xff0c;比如用于日常打電話聯系親朋好友&#xff0c;閑暇時刷短視頻、玩本地安裝的游戲&#xff0c;或者簡單處理一些文檔、郵件等辦公事務。跨境云手機主要是側重于跨境業務場景&#xff0c;對于從事跨境電商…

MemGPT: Towards LLMs as Operating Systems

1 MemGPT: Towards LLMs as Operating Systems 論文地址&#xff1a;MemGPT: Towards LLMs as Operating Systems 代碼地址&#xff1a;https://github.com/letta-ai/letta 1.1 MemGPT MemGPT&#xff08;MemoryGPT&#xff09;借鑒傳統操作系統的分層內存管理思想&#xff08;…

MICAPS:氣象信息綜合分析與處理系統概述

1.概述 說明:Meteorological Information Comprehensive Analysis and Process System 中文意思:氣象信息綜合分析處理系統。它是中國氣象局開發的一套氣象數據分析、處理和可視化系統,用于氣象資料的收集、整理、分析和發布。 2.MICAPS 的用途 說明: 數據收集:接收來自…

MySQL-day2_02

MySQL-day2&#xff08;四&#xff09;排序&#xff08;五&#xff09;聚合函數一、count 總記錄數二、max 最大值三、min 最小值四、sum 求和五、avg 平均值&#xff08;六&#xff09;數據分組一、分組二、分組后的數據篩選&#xff08;七&#xff09;數據分頁顯示一、獲取部…

HarmonyOS應用開發:深入ArkUI聲明式開發范式與最佳實踐

HarmonyOS應用開發&#xff1a;深入ArkUI聲明式開發范式與最佳實踐 引言 隨著HarmonyOS 4.0的發布及API 12的推出&#xff0c;華為的分布式操作系統進入了全新的發展階段。ArkUI作為HarmonyOS應用開發的核心框架&#xff0c;其聲明式開發范式&#xff08;Declarative Paradigm&…

Claude-Flow AI協同開發:鉤子系統與 GitHub 集成

5.1 思維認知框架&#xff1a;從“開發助手”到“DevOps 智能體” 在此之前&#xff0c;我們將 Claude-Flow 視為一個強大的 “開發助手 (Development Assistant)” &#xff0c;它在編碼、測試、重構等環節為我們提供支持。現在&#xff0c;我們需要再次進行思維升級&#xff…

DigitalOcean Kubernetes 現已支持 Gateway API 托管服務

在 DigitalOcean Kubernetes 集群中管理流量&#xff0c;一直以來主要依賴 Ingress。雖然能滿足基本需求&#xff0c;但在靈活性、角色分離和高級路由方面仍存在局限。今天&#xff0c;我們很高興迎來新的改變。 我們正式宣布&#xff0c;Kubernetes Gateway API 托管服務現已…

聚銘網絡入選數世咨詢《中國數字安全價值圖譜》“日志審計”推薦企業

近日&#xff0c;國內知名數字安全咨詢機構數世咨詢正式發布《中國數字安全價值圖譜》。聚銘網絡憑借領先的技術實力與出色的市場表現&#xff0c;成功入選“日志審計”領域重點推薦企業&#xff0c;彰顯了在該賽道的專業認可與品牌影響力。關于《中國數字安全價值圖譜》 在當下…

豆包、Kimi、通義千問、DeepSeek、Gamma、墨刀 AI”六款主流大模型(或 AI 平臺)生成 PPT 的完整流程

、先厘清 3 個概念&#xff0c;少走彎路大模型 ≠ PPT 軟件豆包、Kimi、通義千問、DeepSeek 本身只負責“出大綱/出文案”&#xff0c;真正的“一鍵配圖排版”要靠官方 PPT 助手或第三方平臺&#xff08;博思 AiPPT、迅捷 AiPPT、Gamma、墨刀 AI 等&#xff09;。兩條主流技術路…

Redis哈希(Hash):適合存儲對象的數據結構,優勢與坑點解析

Redis哈希&#xff08;Hash&#xff09;&#xff1a;適合存儲對象的數據結構&#xff0c;優勢與坑點解析 1. Redis哈希概述 1.1 什么是Redis哈希 Redis哈希&#xff08;Hash&#xff09;是一種映射類型&#xff08;Map&#xff09;&#xff0c;由多個字段值對&#xff08;fi…

Python的uv包管理工具使用

一、簡介 uv是一個繼Python版本管理、Python包管理、項目管理、虛擬環境管理于一體的工具&#xff0c;由于底層是用Rust編寫的&#xff0c;uv的執行速度非常快。 安裝 pip install uv鏡像源設置 uv默認安裝包是從pypi上下載的&#xff0c;速度比較慢。我們可以設置鏡像源&#…

JavaScript事件機制與性能優化:防抖 / 節流 / 事件委托 / Passive Event Listeners 全解析

目標&#xff1a;把“為什么慢、卡頓從哪來、該怎么寫”一次說清。本文先講事件傳播與主線程瓶頸&#xff0c;再給出四件法寶&#xff08;防抖、節流、事件委托、被動監聽&#xff09;&#xff0c;最后用一套可復制的工具函數 清單收尾。1&#xff09;先理解“為什么會卡”&am…

【Chrome】chrome 調試工具的network選項卡,如何同時過濾出doc js css

通過類型按鈕快速篩選&#xff08;更直觀&#xff09;在 Network 選項卡中&#xff0c;找到頂部的 資源類型按鈕欄&#xff08;通常在過濾器搜索框下方&#xff09;。按住 Ctrl 鍵&#xff08;Windows/Linux&#xff09;或 Command 鍵&#xff08;Mac&#xff09;&#xff0c;同…

Elasticsearch (ES)相關

在ES中&#xff0c;已經有Term Index&#xff0c;那還會走倒排索引嗎 你這個問題問得很到位 &#x1f44d;。我們分清楚 Term Index 和 倒排索引 在 Elasticsearch (ES) 里的關系&#xff1a;1. 倒排索引&#xff08;Inverted Index&#xff09; 是 Lucene/ES 檢索的核心。文檔…

pre-commit run --all-files 報錯:http.client.RemoteDisconnected

報錯完整信息初步原因是這樣 報錯是 Python 的 http.client.RemoteDisconnected&#xff0c;意思是 在用 urllib 請求遠程 URL 時&#xff0c;遠程服務器直接斷開了連接&#xff0c;沒有返回任何響應。在你的堆棧里&#xff0c;它出現在 pre-commit 嘗試安裝 Golang 環境的時候…

【C++】STL·List

1. list的介紹及使用 1.1list介紹 List文檔介紹 1.2 list的使用 list中的接口比較多&#xff0c;此處類似&#xff0c;只需要掌握如何正確的使用&#xff0c;然后再去深入研究背后的原理&#xff0c;已 達到可擴展的能力。以下為list中一些常見的重要接口。 1.2.1 list的構造…

圖論2 圖的數據結構表示

目錄 一 圖的數據結構表示 1 鄰接矩陣&#xff08;Adjacency Matrix&#xff09; 2 鄰接表&#xff08;Adjacency List&#xff09; 3 邊列表&#xff08;Edge List&#xff09; 4 十字鏈表&#xff08;Orthogonal List / Cross-linked List, 十字鏈表&#xff09; 5 鄰接…

在Excel中刪除大量間隔空白行

在 Excel 中刪除大量間隔空白行&#xff0c;可使用定位空值功能來快速實現。以下是具體方法&#xff1a;首先&#xff0c;選中包含空白行的數據區域。可以通過點擊數據區域的左上角單元格&#xff0c;然后按住鼠標左鍵拖動到右下角最后一個單元格來實現。接著&#xff0c;按下快…

【C 學習】10-循環結構

“知道做不到就是不知道”一、條件循環1. while只要條件為真&#xff08;true&#xff09;&#xff0c;就會重復執行循環體內的代碼。while (條件) {// 循環體&#xff08;要重復執行的代碼&#xff09; }//示例 int i 1; while (i < 5) {printf("%d\n", i);i; …