Spring Boot 的注解是如何生效的

在這里插入圖片描述
在這里插入圖片描述

在 Spring 中,@Configuration@ComponentScan@Bean@Import 等注解的掃描、解析和 BeanDefinition 注冊是一個分層處理的過程。下面我們以 @Configuration為例,結合代碼流程詳細說明其從掃描到注冊的完整邏輯。

1. 整體流程概覽

以下是核心步驟的流程圖:

1. 掃描候選配置類 → 2. 解析注解元數據 → 3. 注冊 BeanDefinition

具體分為以下階段:

  1. 掃描階段:通過 BeanDefinitionRegistry 獲取所有候選配置類。
  2. 解析階段:使用 ConfigurationClassParser 解析注解(如 @ComponentScan@Bean@Import)。
  3. 注冊階段:通過 ConfigurationClassBeanDefinitionReader 將解析結果注冊為 BeanDefinition

2. 詳細步驟解析

2.1 掃描階段:識別候選配置類

觸發入口
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
邏輯

  1. BeanDefinitionRegistry 獲取所有已注冊的 BeanDefinition 名稱:
    String[] beanNames = registry.getBeanDefinitionNames();
    
  2. 遍歷這些名稱,檢查對應的 BeanDefinition 是否是候選配置類:
    • 條件:類上有 @Configuration@Component@ComponentScan@Import@ImportResource,或類中有 @Bean 方法。
    • 判斷邏輯
      if (isFullConfigurationCandidate(beanDef) || isLiteConfigurationCandidate(beanDef)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
      
    • isFullConfigurationCandidate(beanDef):檢查是否有 @Configuration 注解。
    • isLiteConfigurationCandidate(beanDef):檢查是否有其他相關注解(如 @Component@Bean 方法)。

關鍵點

  • 掃描的輸入是已注冊的 BeanDefinition(可能來自 XML、Java Config 或自動掃描)。
  • 此時尚未解析注解內容,僅識別出需要進一步處理的候選類。

2.2 解析階段:處理注解元數據

核心類ConfigurationClassParser
入口方法parse()
邏輯:遞歸解析每個候選配置類的注解。

(1) 解析 @ComponentScan
  • 作用:掃描指定包路徑下的 @Component 類(如 @Service@Repository)。
  • 流程
    1. 獲取 @ComponentScan 注解的 basePackagesbasePackageClasses
    2. 使用 ClassPathBeanDefinitionScanner 掃描類路徑:
      scanner.scan(basePackages);
      
    3. 掃描到的類會被注冊為新的 BeanDefinition(類型為 ScannedGenericBeanDefinition)。
  • 關鍵點
    • 掃描時使用 ASM 或反射讀取類注解,避免提前加載類到 JVM。
    • 新注冊的 BeanDefinition 可能也會被后續解析(如果它們也是配置類)。
(2) 解析 @Bean 方法
  • 作用:將配置類中的 @Bean 方法轉換為 BeanDefinition
  • 流程
    1. 遍歷配置類中的所有方法,篩選帶 @Bean 注解的方法。
    2. 為每個 @Bean 方法生成一個 BeanDefinition
      • 類型ConfigurationClassBeanDefinition
      • 工廠方法:設置為 @Bean 方法(通過 factoryMethodNamefactoryBeanName 指定)。
      • 依賴:解析 @Bean 方法的參數(按類型或 @Qualifier 注入)。
  • 示例
    @Configuration
    public class AppConfig {@Beanpublic DataSource dataSource() {return new HikariDataSource();}
    }
    
    • 生成的 BeanDefinition 會記錄:factoryBeanName=appConfig, factoryMethodName=dataSource
(3) 解析 @Import
  • 作用:動態導入其他配置類或 BeanDefinition
  • 三種處理方式
    1. 普通類:直接注冊為 BeanDefinition
      @Import(OtherConfig.class)
      
    2. ImportSelector:通過編程方式選擇要導入的類。
      @Import(MyImportSelector.class)
      
      • MyImportSelector 實現 selectImports() 方法,返回要導入的類名數組。
    3. ImportBeanDefinitionRegistrar:直接注冊 BeanDefinition
      @Import(MyRegistrar.class)
      
      • MyRegistrar 實現 registerBeanDefinitions() 方法,手動操作 BeanDefinitionRegistry
(4) 處理父類與接口
  • 遞歸檢查配置類的父類和接口,確保不遺漏任何 @Bean 方法或元注解。

2.3 注冊階段:加載 BeanDefinition

核心類ConfigurationClassBeanDefinitionReader
入口方法loadBeanDefinitions()
邏輯:將解析結果(ConfigurationClass 對象)轉換為 BeanDefinition 并注冊到容器。

(1) 注冊 @Import 的類
  • 普通類:通過 registry.registerBeanDefinition() 直接注冊。
  • ImportBeanDefinitionRegistrar:調用其 registerBeanDefinitions() 方法。
(2) 注冊 @Bean 方法
  • 為每個 @Bean 方法生成 BeanDefinition 并注冊:
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    
(3) 處理嵌套配置類
  • 如果配置類內部有 @Configuration 靜態嵌套類,遞歸處理。

3. 關鍵設計點

(1) 延遲加載與遞歸處理

  • 延遲加載@ComponentScan 掃描到的類可能也是配置類,需要遞歸解析。
  • 循環依賴處理:Spring 通過提前暴露 BeanDefinition 解決配置類之間的循環引用。

(2) 元數據存儲

  • ConfigurationClass 對象存儲解析后的中間結果(如 @Bean 方法、@Import 類等)。
  • BeanDefinitionattribute 字段存儲配置類的元信息(如 @Lazy@Primary)。

(3) 性能優化

  • ASM 字節碼分析:在掃描階段避免加載類到 JVM。
  • 緩存:解析結果緩存到 ConfigurationClass 中,避免重復處理。

4. 示例全流程

場景

@Configuration
@ComponentScan("com.example.service")
@Import(OtherConfig.class)
public class AppConfig {@Beanpublic DataSource dataSource() {return new HikariDataSource();}
}

步驟

  1. 掃描階段
    • 發現 AppConfig 是候選配置類(有 @Configuration)。
  2. 解析階段
    • 解析 @ComponentScan:掃描 com.example.service 包,注冊 @Service 類。
    • 解析 @Import(OtherConfig.class):遞歸處理 OtherConfig
    • 解析 @Bean dataSource():生成工廠方法 BeanDefinition
  3. 注冊階段
    • 注冊 OtherConfig 及其 @Bean 方法。
    • 注冊 dataSourceBeanDefinition

5. 總結

Spring 對配置類注解的處理是一個分層遞歸的過程:

  1. 掃描:通過 BeanDefinitionRegistry 篩選候選類。
  2. 解析ConfigurationClassParser 解析注解并生成中間結果(ConfigurationClass)。
  3. 注冊ConfigurationClassBeanDefinitionReader 將解析結果轉換為 BeanDefinition

這種設計將注解元數據解析與 BeanDefinition 注冊分離,確保了靈活性和擴展性(如支持動態 ImportSelector)。同時,遞歸處理和緩存機制解決了復雜依賴和性能問題。

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

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

相關文章

Django REST Framework響應類Response詳解

概述 Response 類是一個智能的 HTTP 響應類,能夠根據客戶端請求的內容類型(Content-Type)自動將數據渲染成合適的格式(JSON、XML、HTML等)。 基本用法 from rest_framework.response import Response# 最簡單的用法 de…

# 小程序 Web 登錄流程完整解析

登錄流程完整小白解析(小程序 & Web) 在開發中,登錄是每個系統最基礎的功能。為了讓小白也能理解,我們用通俗類比和流程講解 小程序登錄、Web 登錄、Token 刷新、安全存儲等整個過程。1?? 小程序登錄流程(小白理…

安裝vcenter6.7 第二階段安裝很慢 或卡在50%

DNS、FQDN配置的問題采用VCSA安裝vCenter時,第一步安裝還算順利,第二步就會安裝失敗,而且還特別慢,這是因為部署時需要DNS服務器,下面就是不采用DNS服務器的部署方案。第一步:正常安裝,DNS就寫本…

第十六屆藍橋杯軟件賽 C 組省賽 C++ 題解

大家好,今天是 2025 年 9 月 11 日,我來給大家寫一篇關于第十六屆藍橋杯軟件賽 C 組省賽的C 題解,希望對大家有所幫助!!! 創作不易,別忘了一鍵三連 題目一:數位倍數 題目鏈接&…

項目幫助文檔的實現

項目幫助文檔的實現 代碼如下&#xff1a; #ifndef __M_HELPER_H__ #define __M_HELPER_H__ #include <iostream> #include <fstream> #include <string> #include <vector> #include <sqlite3.h> #include <random> #include <sstream…

python逆向-逆向pyinstaller打包的exe程序反編譯獲取源代碼

python逆向-逆向pyinstaller打包的exe程序反編譯獲取源代碼 Pyinstaller pyinstaller 是一個用于將 Python 程序打包成獨立可執行文件的工具&#xff0c;能夠在沒有 Python 解釋器的情況下運行。 Python 腳本轉換為 Windows、macOS 和 Linux 操作系統上的可執行文件。 把Python…

【SQL】-- sql having 和 where 的 區別

HAVING 和 WHERE 都是用來篩選數據的&#xff0c;但它們的應用場景有所不同。WHERE&#xff1a;用于篩選行數據&#xff0c;通常在 FROM 子句之后執行。它在分組操作 (GROUP BY) 之前應用&#xff0c;用來篩選出符合條件的記錄。示例&#xff1a;SELECT name, age FROM employe…

MySQL,SQL Server,PostgreSQL三種數據庫各自的優缺點,分別適用哪些場景

MySQL的優缺點及適用場景優點開源免費&#xff0c;社區版可商用&#xff0c;成本低。輕量級&#xff0c;安裝配置簡單&#xff0c;適合中小型項目。讀寫性能優異&#xff0c;尤其在OLTP&#xff08;在線事務處理&#xff09;場景下表現突出。支持主從復制、分片等擴展方案&…

Java 類加載機制雙親委派與自定義類加載器

我們來深入解析 Java 類加載機制。這是理解 Java 應用如何運行、如何實現插件化、以及解決一些依賴沖突問題的關鍵。一、核心概念&#xff1a;類加載過程一個類型&#xff08;包括類和接口&#xff09;從被加載到虛擬機內存開始&#xff0c;到卸載出內存為止&#xff0c;它的整…

Kaggle項目實踐——Titanic: Machine Learning from Disaster

泰坦尼克號沉船事件是機器學習領域最經典的入門項目之一。Kaggle 上的 Titanic: Machine Learning from Disaster 競賽&#xff0c;被無數人稱為“機器學習的 Hello World”。 一、數據導入與清洗&#xff1a;讓數據從 “雜亂” 變 “干凈” 機器學習模型就像 “挑食的孩子”…

Qt C++ 復雜界面處理:巧用覆蓋層突破復雜界面處理難題?之二

接上一篇&#xff0c;繼續探索“覆蓋層”的使用方法。 五、覆蓋層進階交互&#xff1a;從 “能繪制” 到 “好操作”? 基礎的繪制功能只能滿足 “看得見” 的需求&#xff0c;實際開發中還需要 “能操作”—— 比如選中線條修改顏色、按 Delete 鍵刪除線條、鼠標 hover 時高亮…

神經網絡構成框架-理論學習

一、神經網絡的基本組成與分類 1.1 神經網絡的核心組成部分 神經網絡是現代人工智能的基石&#xff0c;其設計靈感來源于生物神經系統的信息處理方式。作為工程師&#xff0c;了解神經網絡的基本組成部分對于構建和優化模型至關重要。一個典型的神經網絡主要由以下幾個關鍵部分…

從0開始開發app(AI助手版)-架構及環境搭建

架構選擇 前端React Native 后端Firebase 原因 環境準備 安裝node 安裝JDK 命令行工具&#xff1a;Node.js command prompt命令行查詢Javav版本&#xff1a;javac -version使用nrm工具切換淘寶源&#xff1a;npx nrm use taobao安裝yarn&#xff0c;替代npm下載工具&#x…

【性能測試】Jmeter工具快速上手-搭建壓力測試腳本

&#x1f525;個人主頁&#xff1a; 中草藥 &#x1f525;專欄&#xff1a;【Java】登神長階 史詩般的Java成神之路 概念 性能測試是軟件測試的重要分支&#xff0c;核心目標是通過模擬真實業務場景和負載壓力&#xff0c;評估系統在不同條件下的性能表現&#xff0c;發現系統性…

oracle里的int類型

oracle里的int類型 在 ANSI SQL 標準 中&#xff0c;INTEGER 和 SMALLINT 是定義好的精確數值類型&#xff0c;但它們的 “長度”或“大小”并不是通過 (N) 括號來指定的&#xff08;如 INT(4)&#xff09;&#xff0c;這一點與 MySQL 等數據庫的非標準擴展完全不同。 SMALLI…

前端學習之后端java小白(二)-sql約束/建表

一、約束SQL約束&#xff08;Constraints&#xff09;是用于限制表中數據的規則&#xff0c;確保數據的完整性和準確性。以下是主要的SQL約束類型&#xff1a; 主要約束類型&#xff1a; 1. NOT NULL 約束: 確保列不能包含空值 CREATE TABLE users (id INT NOT NULL,name VARC…

OpenCV:圖像金字塔

文章目錄一、什么是圖像金字塔&#xff1f;二、圖像金字塔的核心操作&#xff1a;采樣與逆采樣1. 向下采樣&#xff08;pyrDown&#xff09;&#xff1a;從高分辨率到低分辨率步驟1&#xff1a;高斯濾波步驟2&#xff1a;刪除偶數行與偶數列OpenCV實戰代碼效果特點2. 向上采樣&…

LVS與Keepalived詳解(一)負載均衡集群介紹

文章目錄前言一、什么是LVS&#xff1f;二、四層&#xff08;L4&#xff09;負載均衡的最佳解決方案是什么&#xff1f;2.1解決方案分類與對比&#xff08;負載均衡的三種方式介紹&#xff09;2.1.1 硬件負載均衡 (Hardware Load Balancer)2.1.2 軟件負載均衡 (Software Load B…

消息隊列-kafka完結

基本概念和操作 基本概念 簡單概念:::color4 Broker&#xff1a;如果將kafka比喻成數據倉庫網絡&#xff0c;那么Broker就是網絡中的倉庫節點&#xff0c;比如快遞站&#xff0c;在該節點內可以獨立運行&#xff0c;并且多個Broker可以連接起來&#xff0c;構建kafka集群Topic&…

Chromium 138 編譯指南 Windows篇:環境變量配置與構建優化(三)

引言配置&#xff0c;往往決定成敗。在軟件開發的世界里&#xff0c;環境變量就像是一位無聲的指揮家&#xff0c;默默地協調著各個組件的協同工作。對于Chromium 138這樣一個擁有數千萬行代碼的超大型項目而言&#xff0c;正確的環境變量配置更是編譯成功的關鍵所在。也許您曾…