Spring 源碼解析CommonAnnotationBeanPostProcessor
概述
基于 Spring Framework v5.2.6.RELEASE
前面的幾篇文章,通過(guò)源碼分析了 AnnotationConfigApplicationContext 初始化時(shí)注冊(cè)的兩個(gè)關(guān)鍵的后處理器 ConfigurationClassPostProcessor 和 AutowiredAnnotationBeanPostProcessor 的作用和工作原理,本文接著介紹第三個(gè)關(guān)鍵的后處理器 CommonAnnotationBeanPostProcessor。
以下是 Spring 上下文初始化過(guò)程中,CommonAnnotationBeanPostProcessor 被注冊(cè)的代碼片段。這段代碼在 AnnotationConfigUtils 類的registerAnnotationConfigProcessors方法中。
registerAnnotationConfigProcessors
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
從代碼的注釋中可以看到,這個(gè)后處理器的作用,是為了適配 JSR-250 的特性,關(guān)于 JSR-250 是什么,會(huì)在下文中介紹。
除此之外,除了判斷當(dāng)前的容器是否已經(jīng)注冊(cè)了這個(gè)后處理器外,還有一個(gè)判斷條件是jsr250Present,這個(gè)變量的初始化可以在 AnnotationConfigUtils 類中的靜態(tài)代碼塊里找到:
jsr250Present = ClassUtils.isPresent("javax.annotation.Resource", classLoader);
其實(shí)就是看能不能加載到javax.annotation.Resource類型,如果能,則jsr250Present的值就是true。也就是說(shuō),如果能加載到javax.annotation.Resource類型,說(shuō)明當(dāng)前 Spring 運(yùn)行的環(huán)境是支持 JSR-250 特性的,只有在這種條件下,Spring 才需要注冊(cè) CommonAnnotationBeanPostProcessor 后處理器。
說(shuō)了這么多,我們有必要先了解一下 JSR-250 是什么。
JSR 和 JSR-250
JSR 是 Java Specification Requests 的縮寫,意思是「Java 規(guī)范提案」,是 Java 平臺(tái)重要的技術(shù)標(biāo)準(zhǔn)。JSR 由開(kāi)放組織 JCP(Java Community Process)維護(hù),任何組織成員都可以提出 JSR 提案,以向 Java 平臺(tái)提供新的規(guī)范和技術(shù),經(jīng)過(guò)公開(kāi)審查和 JCP 執(zhí)行委員會(huì)的投票,JSR 會(huì)最終成為正式的標(biāo)準(zhǔn)。
JSR-250 的全稱是 Common Annotations for the JavaTM Platform,也就是 Java 平臺(tái)的公共注解。這也是本文要介紹的后處理器名字叫 CommonAnnotationBeanPostProcessor 的原因。
參考鏈接:The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 250
JSR-250 注解可以在javax.annotation包下找到。

我們打開(kāi)其中的一個(gè)注解的源碼,比如 Resource 的源碼。

可以看到,注釋中標(biāo)記了支持該注解的 JDK 起始版本之外,還注明了起始的 Common Annotations 版本。
了解這些之后,我們回到 Spring 的源碼,開(kāi)始分析 CommonAnnotationBeanPostProcessor 后處理器。
CommonAnnotationBeanPostProcessor 分析
根據(jù)慣例,還是先從它的類繼承關(guān)系下手。

可以看到,它是一個(gè) BeanPostProcessor 的實(shí)現(xiàn)類,實(shí)現(xiàn)了4個(gè) Bean 后處理器接口,并繼承了 InitDestroyAnnotationBeanPostProcessor 類。
我們?cè)倏匆幌滤鼘?shí)現(xiàn)的這些接口中,定義了哪些后處理方法。

要分析 Spring 是如何通過(guò) CommonAnnotationBeanPostProcessor 來(lái)支持 JSR-250 特性的,就需要從這些方法下手。我們可以從 CommonAnnotationBeanPostProcessor 和它的父類 InitDestroyAnnotationBeanPostProcessor 的源碼中,查找它們實(shí)現(xiàn)了哪些處理方法??偨Y(jié)如下:
CommonAnnotationBeanPostProcessor 主要在postProcessMergedBeanDefinition和postProcessProperties方法中增加了處理邏輯。InitDestroyAnnotationBeanPostProcessor 則主要在postProcessBeforeInitialization和postProcessBeforeDestruction方法中增加了處理邏輯。
最后,再簡(jiǎn)單地介紹一下這幾個(gè)后處理方法被調(diào)用的時(shí)機(jī):
postProcessMergedBeanDefinition在通過(guò)doCreateBean使用反射機(jī)制創(chuàng)建 Bean 實(shí)例之后調(diào)用。postProcessProperties在裝配 Bean 實(shí)例的屬性前對(duì)屬性進(jìn)行處理。postProcessBeforeInitialization在 Bean 實(shí)例的初始化方法執(zhí)行前被調(diào)用。postProcessBeforeDestruction在 Bean 實(shí)例的銷毀方法執(zhí)行前被調(diào)用。
Spring 主要對(duì)@Resource、@PostConstruct和@PreDestroy三個(gè) JSR-250 注解提供了支持,其實(shí)根據(jù)三個(gè)注解的名稱,和以上介紹的幾個(gè)后處理方法被調(diào)用的時(shí)機(jī),就能知道它們的對(duì)應(yīng)關(guān)系。具體的工作原理,我們放到之后的文章中介紹。
總結(jié)
本文介紹了 CommonAnnotationBeanPostProcessor 后處理器的作用、它主要實(shí)現(xiàn)的后處理方法,還順便介紹了 JSR 和 JSR-250 是什么。之后的文章,將深入分析這幾個(gè)后處理器方法分別做了哪些工作,更多關(guān)于Spring CommonAnnotationBeanPostProcessor的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過(guò)程詳細(xì)分析
這篇文章主要介紹了SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過(guò)程,單點(diǎn)登錄英文全稱Single?Sign?On,簡(jiǎn)稱就是SSO。它的解釋是:在多個(gè)應(yīng)用系統(tǒng)中,只需要登錄一次,就可以訪問(wèn)其他相互信任的應(yīng)用系統(tǒng)2022-12-12
詳解Spring中使用xml配置bean的細(xì)節(jié)
本篇文章主要介紹了Spring中使用xml配置bean的細(xì)節(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
Java開(kāi)發(fā)環(huán)境不再需要配置classpath問(wèn)題
這篇文章主要介紹了Java開(kāi)發(fā)環(huán)境不再需要配置classpath問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
詳解spring mvc對(duì)異步請(qǐng)求的處理
spring mvc3.2及以上版本增加了對(duì)請(qǐng)求的異步處理,是在servlet3的基礎(chǔ)上進(jìn)行封裝的,有興趣的可以了解一下。2017-01-01
通過(guò)端口1433連接到主機(jī)127.0.0.1的 TCP/IP 連接失敗,錯(cuò)誤:“connect timed out”的解
這篇文章主要介紹了通過(guò)端口1433連接到主機(jī)127.0.0.1的 TCP/IP 連接失敗,錯(cuò)誤:“connect timed out”的解決方法,需要的朋友可以參考下2015-08-08
Java8通過(guò)Function獲取字段名的方法(獲取實(shí)體類的字段名稱)
Java8通過(guò)Function獲取字段名。不用再硬編碼,效果類似于mybatis-plus的LambdaQueryWrapper,對(duì)Java8通過(guò)Function獲取字段名相關(guān)知識(shí)感興趣的朋友一起看看吧2021-09-09
基于Java實(shí)現(xiàn)ssh命令登錄主機(jī)執(zhí)行shell命令過(guò)程解析
這篇文章主要介紹了基于Java實(shí)現(xiàn)ssh命令登錄主機(jī)執(zhí)行shell命令過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之隊(duì)列
這篇文章主要介紹了Java隊(duì)列數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),隊(duì)列是一種特殊的線性表,只允許在表的隊(duì)頭進(jìn)行刪除操作,在表的后端進(jìn)行插入操作,隊(duì)列是一個(gè)有序表先進(jìn)先出,想了解更多相關(guān)資料的小伙伴可以參考下面文章的詳細(xì)內(nèi)容2022-02-02

