电竞比分网-中国电竞赛事及体育赛事平台

分享

@ConditionalOnProperty的使用與原理

 gideshi 2020-02-08


一、宏觀理解

通過(guò)字面意思可以看出,它依據(jù)配置文件的內(nèi)容作為條件。那么作為條件后,他又有什么用處呢?

點(diǎn)擊這個(gè)注解,我們可以看出這是一個(gè)基于springboot自動(dòng)化配置的注解,它作用于接口、類(lèi)、枚舉、注解、方法之上。

本文以下面這個(gè)方法為例,也是真實(shí)項(xiàng)目中的一個(gè)例子:基本使用很簡(jiǎn)單,增加注解并且配置name和havingValue屬性

目的是針對(duì)不同的配置,注冊(cè)不同的配置bean。

如下圖所示

同時(shí)它還組合了注解@Conditional({OnPropertyCondition.class}),conditional注解是springframework的功能,內(nèi)部只有一個(gè)屬性那就是一個(gè)class文件數(shù)組。通過(guò)上圖和下面的圖示我們可以看出,springboot的ConditionalOnProperty其實(shí)是組合了@Conditional({OnPropertyCondition.class}),OnPropertyCondition.class究竟是什么,我們一起來(lái)看看。

二、OnPropertyCondition.class

下面我們來(lái)看看這個(gè)類(lèi)究竟要干些什么,我們開(kāi)始不必很細(xì)致的精讀每一行代碼,先做一個(gè)粗略的認(rèn)知

@Order(-2147483608)表示這是一個(gè)比較高優(yōu)先級(jí)的bean,他要先于其他的bean被初始化。這也于是這他的用途,根據(jù)配置初始化合適的bean。

@Order(-2147483608)class OnPropertyCondition extends SpringBootCondition {OnPropertyCondition() {}public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {。。。}private List<AnnotationAttributes> annotationAttributesFromMultiValueMap(MultiValueMap<String, Object> multiValueMap) {。。。return annotationAttributes;}private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) {。。。}private static class Spec {private final String prefix;private final String havingValue;private final String[] names;private final boolean matchIfMissing;Spec(AnnotationAttributes annotationAttributes) {。。。}private String[] getNames(Map<String, Object> annotationAttributes) {。。。}private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) {。。。}private boolean isMatch(String value, String requiredValue) {。。。}public String toString() {。。。return result.toString();}}}

先根據(jù)方法名猜測(cè)一下,這些方法大致是:

1、public getMatchOutcome 獲取匹配的結(jié)果
2、private annotationAttributesFromMultiValueMap 根據(jù)多個(gè)值,映射注解屬性
3、private determineOutcome 決定匹配的結(jié)果
4、private getNames 獲取名稱(chēng)
5、private collectProperties 收集屬性
6、private isMatch 判斷是否匹配
7、public toString 打印字符串

由此帶著猜想我們?cè)谶@些方法上打斷點(diǎn),首先進(jìn)入方法1,參數(shù)里metadata就是我們加上@ConditionalOnProperty注解的類(lèi)或方法的元數(shù)據(jù)信息。

按下F6,我們發(fā)現(xiàn)他進(jìn)入了私有方法2:annotationAttributesFromMultiValueMap,如下圖所示。我們發(fā)現(xiàn)這里的multiValueMap其實(shí)是一系列固定的鍵值對(duì),這段代碼的作用就是將MulitValueMap參數(shù)轉(zhuǎn)換成AnnotationAttributes的list對(duì)象

最后的產(chǎn)出是一個(gè)annotationAttribute對(duì)象 ,可以看到這里的key value集合跟最開(kāi)始我們配置注解的地方是吻合的。

下一步,當(dāng)我們拿到了這個(gè)list,跳轉(zhuǎn)至私有方法3:determineOutcome,

注意這里的第一個(gè)參數(shù) annotationAttribute不必解釋?zhuān)褪悄且淮甼ey value值,后面的context.getEnvironment是獲取當(dāng)前環(huán)境的配置信息,如下圖所示:,可以看到都是我們熟悉的配置信息,其中紅框中的信息便是springboot的application.properties配置文件。由此我們可以斷定,這個(gè)方法就是根據(jù)配置文件與映射對(duì)象去探明,當(dāng)前的這個(gè)condition條件是否匹配,是否成立。

繼續(xù)按F6,我們發(fā)現(xiàn)他去構(gòu)造了一個(gè)內(nèi)部類(lèi)

這個(gè)內(nèi)部類(lèi)里的屬性就是我們注解中配置的內(nèi)容,當(dāng)生成這個(gè)內(nèi)部類(lèi)對(duì)象后,執(zhí)行了方法4:getNames方法。也就是獲取所有的屬性名稱(chēng),如下圖所示:

組裝完對(duì)象后,我們發(fā)現(xiàn)它繼續(xù)執(zhí)行方法5:collectProperties,注意這里的第一個(gè)參數(shù)resolver,他其實(shí)是當(dāng)前系統(tǒng)的配置文件數(shù)據(jù)。而且這個(gè)方法是Spec(內(nèi)部類(lèi))的方法,結(jié)合參數(shù)和方法名也基本猜到了這個(gè)方法的作用,那就是根據(jù)map去配置文件收集對(duì)應(yīng)的屬性,如果存在miss的配置或者不match的屬性,那么missingProperties和nonMatchingProperties將不會(huì)為空,此時(shí)將執(zhí)行下面的判斷步驟

下面我們來(lái)看下collectProperties方法都執(zhí)行了哪些步驟,如下圖所示,我們看到了方法6:isMatch,我們發(fā)現(xiàn)這里的value是“dev”,requireValue是“product”,而這兩個(gè)參數(shù)分別從配置文件和spec對(duì)象中獲取。也印證了isMatch方法的意思,就是期望屬性和配置文件中的屬性是否對(duì)應(yīng)。

如果不對(duì)應(yīng)那么nonMatching.add將會(huì)被執(zhí)行。

最后 determineOutcome返回ConditionOutcome對(duì)象,注意這里的三個(gè)操作

1、如果!missingProperties是空的,也就是說(shuō)沒(méi)有找到屬性的情況下,執(zhí)行noMatch方法

2、否則,當(dāng)找到屬性但是值沒(méi)有匹配上的時(shí)候,執(zhí)行noMatch方法

3、否則,執(zhí)行match方法

if (!missingProperties.isEmpty()) {return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, new Object[]{spec}).didNotFind("property", "properties").items(Style.QUOTE, missingProperties));} else {return !nonMatchingProperties.isEmpty() ? ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, new Object[]{spec}).found("different value in property", "different value in properties").items(Style.QUOTE, nonMatchingProperties)) : ConditionOutcome.match(ConditionMessage.forCondition(ConditionalOnProperty.class, new Object[]{spec}).because("matched"));}

其實(shí)match方法的邏輯很簡(jiǎn)單:主要是返回一個(gè)true狀態(tài)位,一個(gè)ConditionMessage.forCondition(ConditionalOnProperty.class, new Object[]{spec}).because("matched")參數(shù)。這個(gè)參數(shù)返回的是ConditionMessage,也就是一段話(huà),可以不用理會(huì)。

public static ConditionOutcome match(ConditionMessage message) {return new ConditionOutcome(true, message);}

最終如果匹配,返回的這個(gè)true將會(huì)為類(lèi)或者方法的返回值構(gòu)建相應(yīng)的bean實(shí)例。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多