《Spring Boot 源碼學(xué)習(xí)系列》
一、引言
上篇博文《共享 MetadataReaderFactory 上下文初始化器》,Huazie 帶大家詳細(xì)分析了SharedMetadataReaderFactoryContextInitializer
。而在 spring-boot-autoconfigure 子模塊中預(yù)置的上下文初始化器中,除了共享 MetadataReaderFactory
上下文初始化器,還有一個(gè)尚未分析。
那么本篇就來(lái)詳細(xì)分析一下 ConditionEvaluationReportLoggingListener
【即 ConditionEvaluationReport
日志記錄上下文初始化器】。
二、往期內(nèi)容
在開(kāi)始本篇的內(nèi)容介紹之前,我們先來(lái)看看往期的系列文章【有需要的朋友,歡迎關(guān)注系列專欄】:
Spring Boot 源碼學(xué)習(xí) |
Spring Boot 項(xiàng)目介紹 |
Spring Boot 核心運(yùn)行原理介紹 |
【Spring Boot 源碼學(xué)習(xí)】@EnableAutoConfiguration 注解 |
【Spring Boot 源碼學(xué)習(xí)】@SpringBootApplication 注解 |
【Spring Boot 源碼學(xué)習(xí)】走近 AutoConfigurationImportSelector |
【Spring Boot 源碼學(xué)習(xí)】自動(dòng)裝配流程源碼解析(上) |
【Spring Boot 源碼學(xué)習(xí)】自動(dòng)裝配流程源碼解析(下) |
【Spring Boot 源碼學(xué)習(xí)】深入 FilteringSpringBootCondition |
【Spring Boot 源碼學(xué)習(xí)】OnClassCondition 詳解 |
【Spring Boot 源碼學(xué)習(xí)】OnBeanCondition 詳解 |
【Spring Boot 源碼學(xué)習(xí)】OnWebApplicationCondition 詳解 |
【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解 |
【Spring Boot 源碼學(xué)習(xí)】HttpEncodingAutoConfiguration 詳解 |
【Spring Boot 源碼學(xué)習(xí)】RedisAutoConfiguration 詳解 |
【Spring Boot 源碼學(xué)習(xí)】JedisConnectionConfiguration 詳解 |
【Spring Boot 源碼學(xué)習(xí)】初識(shí) SpringApplication |
【Spring Boot 源碼學(xué)習(xí)】Banner 信息打印流程 |
【Spring Boot 源碼學(xué)習(xí)】自定義 Banner 信息打印 |
【Spring Boot 源碼學(xué)習(xí)】BootstrapRegistryInitializer 詳解 |
【Spring Boot 源碼學(xué)習(xí)】ApplicationContextInitializer 詳解 |
【Spring Boot 源碼學(xué)習(xí)】ApplicationListener 詳解 |
【Spring Boot 源碼學(xué)習(xí)】SpringApplication 的定制化介紹 |
【Spring Boot 源碼學(xué)習(xí)】BootstrapRegistry 詳解 |
【Spring Boot 源碼學(xué)習(xí)】深入 BootstrapContext 及其默認(rèn)實(shí)現(xiàn) |
【Spring Boot 源碼學(xué)習(xí)】BootstrapRegistry 初始化器實(shí)現(xiàn) |
【Spring Boot 源碼學(xué)習(xí)】BootstrapContext的實(shí)際使用場(chǎng)景 |
【Spring Boot 源碼學(xué)習(xí)】深入 ApplicationContext 初始化器實(shí)現(xiàn) |
【Spring Boot 源碼學(xué)習(xí)】共享 MetadataReaderFactory 上下文初始化器 |
三、主要內(nèi)容
注意: 以下涉及 Spring Boot 源碼 均來(lái)自版本 2.7.9,其他版本有所出入,可自行查看源碼。
3.1 源碼初識(shí)
我們先來(lái)看看 ConditionEvaluationReportLoggingListener
的部分源碼,如下:
public class ConditionEvaluationReportLoggingListener
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private final Log logger = LogFactory.getLog(getClass());
private ConfigurableApplicationContext applicationContext;
private ConditionEvaluationReport report;
private final LogLevel logLevelForReport;
public ConditionEvaluationReportLoggingListener() {
this(LogLevel.DEBUG);
}
public ConditionEvaluationReportLoggingListener(LogLevel logLevelForReport) {
Assert.isTrue(isInfoOrDebug(logLevelForReport), "LogLevel must be INFO or DEBUG");
this.logLevelForReport = logLevelForReport;
}
// 省略。。。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
if (applicationContext instanceof GenericApplicationContext) {
// Get the report early in case the context fails to load
this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
}
}
// 省略。。。
}
從上述源碼中,我們可以看出 ConditionEvaluationReportLoggingListener
實(shí)現(xiàn)了 ApplicationContextInitializer<ConfigurableApplicationContext>
【即應(yīng)用上下文初始化器接口】,有關(guān) ApplicationContextInitializer
的詳細(xì)介紹,請(qǐng)查看《ApplicationContextInitializer 詳解》。
它有三個(gè)成員變量,分別是:
-
ConfigurableApplicationContext applicationContext
: 應(yīng)用上下文對(duì)象 -
ConditionEvaluationReport report
:條件評(píng)估報(bào)告對(duì)象,用于報(bào)告和記錄條件評(píng)估詳細(xì)信息。 -
LogLevel logLevelForReport
:條件評(píng)估報(bào)告的日志級(jí)別,包含TRACE
,DEBUG
,INFO
,WARN
,ERROR
,FATAL
,OFF
再來(lái)看看構(gòu)造方法,它有兩個(gè):
-
無(wú)參構(gòu)造方法:初始化日志級(jí)別為
DEBUG
【默認(rèn)通過(guò)它實(shí)例化該上下文初始化器】 -
帶
LogLevel
參數(shù)的構(gòu)造方法:Assert.isTrue
是用于驗(yàn)證一個(gè)條件是否為真。通過(guò)isInfoOrDebug
來(lái)判斷日志級(jí)別參數(shù)logLevelForReport
是否是 INFO 或 DEBUG 級(jí)別,如果不是,則會(huì)拋出一個(gè)IllegalArgumentException
異常并顯示錯(cuò)誤信息 “LogLevel must be INFO or DEBUG”。
我們繼續(xù)查看 initialize
方法,可以看到 :
- 首先,初始化成員變量應(yīng)用上下文對(duì)象
applicationContext
,便于后續(xù)使用。 - 然后,向應(yīng)用上下文對(duì)象中添加一個(gè)應(yīng)用監(jiān)聽(tīng)器實(shí)現(xiàn)【即
ConditionEvaluationReportListener
】,這里可查看 3.2 小節(jié)的內(nèi)容。 - 最后,如果
applicationContext
是GenericApplicationContext
的一個(gè)實(shí)例對(duì)象,則通過(guò)ConditionEvaluationReport
的靜態(tài)方法get
來(lái)獲取指定 Bean 工廠中的 條件評(píng)估報(bào)告 實(shí)例對(duì)象。
3.2 ConditionEvaluationReport 監(jiān)聽(tīng)器
下面繼續(xù)來(lái)查看 ConditionEvaluationReportListener
的源碼:
閱讀上述源碼,可以看到 ConditionEvaluationReportListener
實(shí)現(xiàn)了 GenericApplicationListener
接口,繼續(xù)翻看 GenericApplicationListener
接口源碼:
繼續(xù)翻看 SmartApplicationListener
接口源碼:
從上述源碼中,我們發(fā)現(xiàn) GenericApplicationListener
繼承了 SmartApplicationListener
,而 SmartApplicationListener
則繼承了 ApplicationListener<ApplicationEvent>
。
GenericApplicationListener
是 Spring 框架中的一個(gè)接口,它擴(kuò)展了 ApplicationListener
接口,暴露了更多的元數(shù)據(jù),如支持的事件和源類(lèi)型。在 Spring Framework 4.2 及更高版本中,GenericApplicationListener
替代了基于類(lèi)的 SmartApplicationListener
,允許你使用 ResolvableType
來(lái)指定支持的事件類(lèi)型,而不僅僅是 Class
類(lèi)型,這樣就可以在運(yùn)行時(shí)更準(zhǔn)確地解析和匹配事件類(lèi)型。
知識(shí)點(diǎn):
ResolvableType
是 Spring 框架中提供的一個(gè)工具類(lèi),它用于在運(yùn)行時(shí)解析和處理 Java 泛型信息。在 Java 5 引入泛型之后,為了支持泛型,新增了Type
類(lèi)來(lái)表示 Java 中的某種類(lèi)型。然而,反射包中提供的方法在獲取泛型類(lèi)型時(shí),通常返回的是Type
或其子類(lèi)的實(shí)例,使用時(shí)可能需要進(jìn)行繁瑣的強(qiáng)制類(lèi)型轉(zhuǎn)換。ResolvableType
的出現(xiàn)就是為了簡(jiǎn)化對(duì)泛型信息的獲取和處理。它能夠?qū)?Class
、Field
、Method
等描述為ResolvableType
(即轉(zhuǎn)換為Type
),從而方便地進(jìn)行泛型的解析和操作。通過(guò)使用ResolvableType
,你可以輕松地獲取 類(lèi)、接口、屬性、方法 等的泛型信息,而無(wú)需進(jìn)行復(fù)雜的類(lèi)型轉(zhuǎn)換或編寫(xiě)繁瑣的代碼。
現(xiàn)在我們?cè)賮?lái)看看 ConditionEvaluationReportListener
中重寫(xiě)的 supportsEventType(ResolvableType)
方法:
也就是說(shuō),該監(jiān)聽(tīng)器實(shí)際上監(jiān)聽(tīng)是如下兩個(gè)事件:
-
ContextRefreshedEvent
:上下文刷新事件。該事件會(huì)在ApplicationContext
完成初始化或刷新時(shí)發(fā)布。 -
ApplicationFailedEvent
:應(yīng)用啟動(dòng)失敗事件。該事件是在 Spring Boot 應(yīng)用啟動(dòng)失敗時(shí)觸發(fā),一般發(fā)生在ApplicationStartedEvent
事件之后。
我們繼續(xù)查看 ConditionEvaluationReportListener
的核心方法 onApplicationEvent
,發(fā)現(xiàn)它直接調(diào)用了 ConditionEvaluationReportLoggingListener
中的 onApplicationEvent
方法,來(lái)實(shí)現(xiàn)條件評(píng)估報(bào)告的日志打印功能。
3.3 onApplicationEvent 方法
我們繼續(xù)查看 ConditionEvaluationReportLoggingListener
中的 onApplicationEvent
方法:
從上圖中,可以看到這里針對(duì) 3.2 中監(jiān)聽(tīng)器監(jiān)聽(tīng)的兩個(gè)事件分別進(jìn)行了處理,而這里的核心方法就是 logAutoConfigurationReport(boolean)
方法。
繼續(xù)查看 logAutoConfigurationReport(boolean)
方法:
從上圖中,我們可以簡(jiǎn)單總結(jié)一下:
- 首先,如果條件評(píng)估報(bào)告
report
為空,則通過(guò)ConditionEvaluationReport
的靜態(tài)方法get
來(lái)獲取當(dāng)前應(yīng)用上下文指定的 Bean 工廠中的 條件評(píng)估報(bào)告 實(shí)例對(duì)象。 - 判斷
report
中的條件評(píng)估結(jié)果是否為空?- 如果不為空,判斷條件評(píng)估報(bào)告的日志級(jí)別
- 如果是
INFO
級(jí)別 ,則繼續(xù)- 如果當(dāng)前允許記錄
INFO
級(jí)別日志,則按INFO
級(jí)別輸出相關(guān)的條件評(píng)估結(jié)果的日志信息。
- 如果當(dāng)前允許記錄
- 如果是
DEBUG
級(jí)別,則繼續(xù)- 如果當(dāng)前允許記錄
DEBUG
級(jí)別日志,則按DEBUG
級(jí)別輸出相關(guān)的條件評(píng)估結(jié)果的日志信息。
- 如果當(dāng)前允許記錄
- 如果是
- 如果不為空,判斷條件評(píng)估報(bào)告的日志級(jí)別
3.4 條件評(píng)估報(bào)告的打印展示
首先,我們?cè)诋?dāng)前 Spring Boot 項(xiàng)目中設(shè)置當(dāng)前的日志級(jí)別為 DEBUG
【當(dāng)然還可以指定其他日志配置文件,這里不展開(kāi)講了】:
運(yùn)行我們的自測(cè)類(lèi)或者應(yīng)用主類(lèi),可以看到如下的運(yùn)行結(jié)果:
從上述運(yùn)行結(jié)果中,可以看出條件評(píng)估報(bào)告中包含如下的內(nèi)容:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-849894.html
-
Positive matches
:正匹配,即@Conditional
條件為真時(shí),相關(guān)的配置類(lèi)被Spring
容器加載,配置類(lèi)中定義的 bean 和其他組件將被創(chuàng)建并添加到Spring
的應(yīng)用上下文中。 -
Negative matches
:負(fù)匹配,即@Conditional
條件為假時(shí),相關(guān)的配置類(lèi)未被 Spring 容器加載。盡管相關(guān)的配置類(lèi)存在于項(xiàng)目中,但由于某些條件不滿足(如缺少必要的依賴或配置),Spring 容器不會(huì)創(chuàng)建該配置類(lèi)中定義的 bean。 -
Exclusions
:排除,即明確要排除的配置類(lèi),這些被排除的自動(dòng)配置類(lèi)中的組件將不會(huì)被創(chuàng)建。 -
Unconditional classes
:無(wú)條件類(lèi),即自動(dòng)配置類(lèi)不包含任何類(lèi)級(jí)別的條件。與 Positive matches 和 Negative matches 不同,這些類(lèi)不依賴于任何特定的條件來(lái)決定是否加載。它們總是會(huì)被 Spring 容器處理,無(wú)論其他條件如何。
四、總結(jié)
本篇 Huazie 帶大家一起分析了 spring-boot-autoconfigure 子模塊中預(yù)置的另一個(gè)應(yīng)用上下文初始化器實(shí)現(xiàn) ConditionEvaluationReportLoggingListener
,它實(shí)現(xiàn)了條件評(píng)估報(bào)告的打印記錄功能,極大地方便了開(kāi)發(fā)者定位配置類(lèi)加載問(wèn)題。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-849894.html
到了這里,關(guān)于【Spring Boot 源碼學(xué)習(xí)】ConditionEvaluationReport 日志記錄上下文初始化器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!