SpringBoot注解生效原理全解析
Spring Boot 注解生效原理分析
Spring Boot 的注解**(如 @RestController、@Service、@Autowired、@Configuration 等)在開(kāi)發(fā)中使用非常廣泛,但它們為什么能“自動(dòng)生效”?**本文將深入解析其背后的原理。
Spring 注解的生效依賴(lài)于 Spring 容器(ApplicationContext) 和 注解處理器(BeanPostProcessor / ConfigurationClassPostProcessor 等)。
前置:Bean 的聲明與注冊(cè)
@Component、@Service、@Controller、@Repository 等注解,都是用于標(biāo)記一個(gè)類(lèi)為 Spring 管理的 Bean。
生效機(jī)制
1、 @Configuration 、 @Component、@ComponentScan 生效原因如下:
Spring 在啟動(dòng)時(shí),進(jìn)行上下文刷新refreshContex()然后觸發(fā)ConfigurationClassPostProcessor掃描所有 @Configuration 、 @Component等類(lèi)注冊(cè)成BeanDefination, @ComponentScan 觸發(fā)包掃描,找到其他 @Component/@Service/@Controller將其也注冊(cè)成 BeanDefination。
2、自動(dòng)注入 @Autowired 實(shí)現(xiàn)機(jī)制:
@Autowired 的生效依賴(lài):依賴(lài)注入(DI)機(jī)制 和 后置處理器(BeanPostProcessor)。
關(guān)鍵類(lèi):
AutowiredAnnotationBeanPostProcessor 處理 @Autowired 注解。
處理流程:
- AutowiredAnnotationBeanPostProcessor負(fù)責(zé)掃描所有 Bean 中的 @Autowired 注解,決定注入哪一個(gè) Bean。
- DependencyDescriptor描述依賴(lài)關(guān)系,包括類(lèi)型、是否必需、泛型等。
- BeanFactory提供 Bean 實(shí)例,用于實(shí)際注入。
1. 啟動(dòng)入口
SpringApplication.run(App.class, args)
→ 創(chuàng)建ApplicationContext(通常是AnnotationConfigServletWebServerApplicationContext)
→ 調(diào)用refresh()(IOC 容器的核心刷新過(guò)程)。
2.refresh()關(guān)鍵步驟
在 AbstractApplicationContext#refresh() 中有一行核心邏輯:
invokeBeanFactoryPostProcessors(beanFactory);
這里會(huì)執(zhí)行所有 BeanFactoryPostProcessor,其中最重要的是:
?? ConfigurationClassPostProcessor
3.ConfigurationClassPostProcessor的作用
源碼示例圖:

它是專(zhuān)門(mén)為配置類(lèi)服務(wù)的后處理器,主要任務(wù):
- 掃描所有
@Configuration類(lèi)。 - 通過(guò)
postProcessBeanDefinitionRegistry()觸發(fā)配置類(lèi)的掃描和解析 - 交給
ConfigurationClassParser解析成配置模型。 - 交給
ConfigurationClassBeanDefinitionReader轉(zhuǎn)換成BeanDefinition并注冊(cè)到容器。
4.ConfigurationClassParser的職責(zé)
當(dāng) ConfigurationClassPostProcessor 檢測(cè)到配置類(lèi)時(shí),就會(huì)調(diào)用 ConfigurationClassParser 解析。
注意:它不是直接生成 BeanDefinition!
它的作用是:
讀取配置類(lèi)上的元注解信息(通過(guò)
AnnotationMetadata)。根據(jù)不同注解做不同解析:
@Configuration→ 標(biāo)記為配置類(lèi),繼續(xù)處理內(nèi)部的@Bean方法。@Component→ 標(biāo)記為普通組件,后續(xù)注冊(cè)。@ComponentScan→ 觸發(fā)包掃描,找到其他@Component/@Service/@Controller。@Import→ 導(dǎo)入配置類(lèi)或交給ImportSelector/ImportBeanDefinitionRegistrar。@ImportResource→ 加載 XML 配置。
遞歸解析,構(gòu)建出一棵配置類(lèi)的內(nèi)部描述模型:
ConfigurationClass。
?? 它相當(dāng)于 語(yǔ)法分析器,把配置類(lèi)源信息轉(zhuǎn)成中間表示。
5.ConfigurationClassBeanDefinitionReader的職責(zé)
接收
ConfigurationClassParser解析出來(lái)的ConfigurationClass模型。生成并注冊(cè)
BeanDefinition:@Bean方法 → 生成工廠(chǎng)方法對(duì)應(yīng)的 BeanDefinition。@Import導(dǎo)入的類(lèi) → 注冊(cè)。- 包掃描結(jié)果的組件 → 注冊(cè)。
將這些
BeanDefinition放入BeanDefinitionRegistry,等待容器實(shí)例化。
?? 它相當(dāng)于 代碼生成器,把中間表示落地成可用的 Bean 定義。
6. 整體鏈路總結(jié)
SpringApplication.run()→ 創(chuàng)建ApplicationContext。refresh()→ 執(zhí)行invokeBeanFactoryPostProcessors()。ConfigurationClassPostProcessor介入。ConfigurationClassParser解析配置類(lèi) → 生成ConfigurationClass模型。ConfigurationClassBeanDefinitionReader將模型轉(zhuǎn)化為BeanDefinition。BeanDefinitionRegistry注冊(cè)所有 生成的BeanDefinition。- 容器實(shí)例化 → Bean 生效。
?? 核心記憶
ConfigurationClassParser:負(fù)責(zé)解析配置類(lèi) → 生成ConfigurationClass模型。ConfigurationClassBeanDefinitionReader:負(fù)責(zé)將模型轉(zhuǎn)為BeanDefinition并注冊(cè)。- 最終
@Configuration/@Component/@Bean等注解能生效,是因?yàn)檫@套機(jī)制在容器刷新時(shí)自動(dòng)執(zhí)行。
核心流程圖總結(jié)
refresh()
↓ // 容器核心刷新流程入口
invokeBeanFactoryPostProcessors()
↓ // 執(zhí)行 BeanFactoryPostProcessor,增強(qiáng) BeanFactory
ConfigurationClassPostProcessor
↓ // 識(shí)別并處理 @Configuration、@ComponentScan、@Import 等配置類(lèi)
ConfigurationClassParser
↓ // 解析配置類(lèi)注解,生成 ConfigurationClass 模型(中間表示)
ConfigurationClassBeanDefinitionReader
↓ // 將 ConfigurationClass 轉(zhuǎn)換為 BeanDefinition
BeanDefinitionRegistry(注冊(cè) BeanDefinition)
↓ // 將 BeanDefinition 注冊(cè)到 IOC 容器
IOC 容器實(shí)例化 Bean
↓ // 根據(jù) BeanDefinition 實(shí)例化對(duì)象,完成依賴(lài)注入并放入單例池到此這篇關(guān)于SpringBoot注解生效原理全解析的文章就介紹到這了,更多相關(guān)SpringBoot注解生效原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用selenium實(shí)現(xiàn)滑塊驗(yàn)證的處理方法
本文介紹如何用Java的Selenium實(shí)現(xiàn)滑塊驗(yàn)證碼的處理,以及如何通過(guò)分析背景圖片找到需要移動(dòng)的距離,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-09-09
MyBatis-Plus自動(dòng)填充字段的詳細(xì)教程
今天編寫(xiě)一個(gè)詳細(xì)的教程來(lái)介紹如何在?Spring?Boot?項(xiàng)目中使用?MyBatis-Plus?實(shí)現(xiàn)自動(dòng)填充時(shí)間字段(如創(chuàng)建時(shí)間?createTime?和更新時(shí)間?updateTime),可以分為以下幾個(gè)部分,這個(gè)教程將涵蓋從項(xiàng)目配置到自動(dòng)填充的完整過(guò)程,需要的朋友可以參考下2024-08-08
解決JavaWeb-file.isDirectory()遇到的坑問(wèn)題
JavaWeb開(kāi)發(fā)中,使用`file.isDirectory()`判斷路徑是否為文件夾時(shí),需要特別注意:該方法只能判斷已存在的文件夾,若路徑不存在,無(wú)論其實(shí)際是否應(yīng)為文件夾,均會(huì)返回`false`,為了解決這個(gè)問(wèn)題,可以采用正則表達(dá)式進(jìn)行判斷,但要求路徑字符串的結(jié)尾必須添加反斜杠(\)2025-02-02
SpringBoot讀取properties文件配置項(xiàng)過(guò)程解析
這篇文章主要介紹了SpringBoot讀取properties文件配置項(xiàng)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Java對(duì)zip,rar,7z文件帶密碼解壓實(shí)例詳解
在日常業(yè)務(wù)中,會(huì)遇到一些瑣碎文件需要打包到一個(gè)壓縮包中上傳,業(yè)務(wù)方在后臺(tái)接收到壓縮包后自行解壓,然后解析相應(yīng)文件。而且可能涉及安全保密,因此會(huì)在壓縮時(shí)帶上密碼,要求后臺(tái)業(yè)務(wù)可以指定密碼進(jìn)行解壓。本文將用Java解決這一問(wèn)題,需要的可以參考一下2022-07-07
Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序介紹
這篇文章主要介紹了Spring Cloud Gateway 默認(rèn)的filter功能和執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
springboot調(diào)用HTML文件注意事項(xiàng)及說(shuō)明
這篇文章主要介紹了springboot調(diào)用HTML文件注意事項(xiàng)及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
Java微信二次開(kāi)發(fā)(二) Java微信文本消息接口請(qǐng)求與發(fā)送
這篇文章主要為大家詳細(xì)介紹了Java微信二次開(kāi)發(fā)第二篇,Java微信文本消息接口請(qǐng)求與發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04

