SpringBoot之@ConditionalOnProperty注解使用方法
@ConditionalOnProperty:根據(jù)屬性值來(lái)控制類或某個(gè)方法是否需要加載。它既可以放在類上也可以放在方法上。
1、SpringBoot實(shí)現(xiàn)
1.1 設(shè)置配置屬性
在applicatio.properties或application.yml配置isload_bean = true;
#配置是否加載類 is_load_bean: true
1.2 編寫加載類
編寫加載類,使用@Component進(jìn)行注解,為了便于區(qū)分,我們將@ConditionalOnProperty放在方法上。
/** * @author: jiangjs * @description: 使用@ConditionalOnProperty * @date: 2023/4/24 10:20 **/ @Component @Slf4j public class UseConditionalOnProperty { @Value("${is_load_bean}") private String isLoadBean; @Bean @ConditionalOnProperty(value = "is_load_bean",havingValue = "true",matchIfMissing = true) public void loadBean(){ log.info("是否加載當(dāng)前類"); } @Bean public void compareLoadBean(){ log.info("加載bean屬性:" + isLoadBean); } }
啟動(dòng)項(xiàng)目時(shí)輸出打印的日志。如圖:
將配置文件的數(shù)據(jù)信息改成false,則不會(huì)打印出結(jié)果。
2、ConditionalOnProperty屬性與源碼
2.1 屬性
查看@ConditionalOnProperty源碼可以看到該注解定義了幾個(gè)屬性。
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Documented @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { /** * name別名,數(shù)組類型,獲取對(duì)應(yīng)property名稱的值,與name不能同時(shí)使用 */ String[] value() default {}; /** * 屬性前綴,未指定時(shí),自動(dòng)以點(diǎn)"."結(jié)束,有效前綴由一個(gè)或多個(gè)詞用點(diǎn)"."連接。 * 如:spring.datasource */ String prefix() default ""; /** * 屬性名稱,配置屬性完整名稱或部分名稱,可與prefix組合使用,不能與value同時(shí)使用 */ String[] name() default {}; /** * 可與name組合使用,比較獲取到的屬性值與havingValue的值是否相同,相同才加載配置 */ String havingValue() default ""; /** * 缺少該配置屬性時(shí)是否加載,默認(rèn)為false。如果為true,沒(méi)有該配置屬性時(shí)也會(huì)正常加載;反之則不會(huì)生效 */ boolean matchIfMissing() default false; }
2.2 源碼
查看OnPropertyCondition類中國(guó)的getMatchOutcome()方法:
@Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { //獲取所有注解ConditionalOnProperty下的所有屬性match,message List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap( metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName())); List<ConditionMessage> noMatch = new ArrayList<>(); List<ConditionMessage> match = new ArrayList<>(); //遍歷注解中的屬性 for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) { //創(chuàng)建判定的結(jié)果,ConditionOutcome只有兩個(gè)屬性, ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment()); (outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage()); } if (!noMatch.isEmpty()) { //如果有屬性沒(méi)有匹配,則返回 return ConditionOutcome.noMatch(ConditionMessage.of(noMatch)); } return ConditionOutcome.match(ConditionMessage.of(match)); }
在上述源碼中determineOutcome()是關(guān)鍵方法,我們來(lái)看看:
private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) { //初始化 Spec spec = new Spec(annotationAttributes); List<String> missingProperties = new ArrayList<>(); List<String> nonMatchingProperties = new ArrayList<>(); //收集屬性,將結(jié)果賦值給missingProperties,nonMatchingProperties spec.collectProperties(resolver, missingProperties, nonMatchingProperties); if (!missingProperties.isEmpty()) { //missingProperties屬性不為空,說(shuō)明設(shè)置matchIfMissing的是false,則不加載類 return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec) .didNotFind("property", "properties").items(Style.QUOTE, missingProperties)); } if (!nonMatchingProperties.isEmpty()) { //nonMatchingProperties屬性不為空,則設(shè)置的屬性值與havingValue值不匹配,則不加載類 return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnProperty.class, spec) .found("different value in property", "different value in properties") .items(Style.QUOTE, nonMatchingProperties)); } return ConditionOutcome .match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched")); }
Spec是OnPropertyCondition的一個(gè)靜態(tài)內(nèi)部類,初始化@ConditionalOnProperty中的屬性。
private static class Spec { private final String prefix; private final String havingValue; private final String[] names; private final boolean matchIfMissing; //初始化,給各屬性賦值 Spec(AnnotationAttributes annotationAttributes) { String prefix = annotationAttributes.getString("prefix").trim(); if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) { prefix = prefix + "."; } this.prefix = prefix; this.havingValue = annotationAttributes.getString("havingValue"); this.names = getNames(annotationAttributes); this.matchIfMissing = annotationAttributes.getBoolean("matchIfMissing"); } //處理name與value private String[] getNames(Map<String, Object> annotationAttributes) { String[] value = (String[]) annotationAttributes.get("value"); String[] name = (String[]) annotationAttributes.get("name"); //限制了value或name必須指定 Assert.state(value.length > 0 || name.length > 0, "The name or value attribute of @ConditionalOnProperty must be specified"); //value和name只能有一個(gè)存在,不能同時(shí)使用 Assert.state(value.length == 0 || name.length == 0, "The name and value attributes of @ConditionalOnProperty are exclusive"); return (value.length > 0) ? value : name; } private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) { //遍歷names,即value或name的值 for (String name : this.names) { //前綴 + name,獲取配置文件中key String key = this.prefix + name; //驗(yàn)證配置屬性中包含key if (resolver.containsProperty(key)) { //如包含,則獲取key對(duì)應(yīng)的值,與havingValue的值進(jìn)行匹配 if (!isMatch(resolver.getProperty(key), this.havingValue)) { //不匹配則添加到nonMatching nonMatching.add(name); } } else { //驗(yàn)證配置屬性中沒(méi)有包含key,判斷是否配置了matchIfMissing屬性 if (!this.matchIfMissing) { //該屬性不為true則添加到missing中 missing.add(name); } } } } private boolean isMatch(String value, String requiredValue) { //驗(yàn)證requiredValue是否有值 if (StringUtils.hasLength(requiredValue)) { //有值,則進(jìn)行比較,不區(qū)分大小寫 return requiredValue.equalsIgnoreCase(value); } //沒(méi)有值,則驗(yàn)證value是否等于false //這也是為什么name, value不配置值的情況下, 類依然會(huì)被加載的原因 return !"false".equalsIgnoreCase(value); } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append("("); result.append(this.prefix); if (this.names.length == 1) { result.append(this.names[0]); } else { result.append("["); result.append(StringUtils.arrayToCommaDelimitedString(this.names)); result.append("]"); } if (StringUtils.hasLength(this.havingValue)) { result.append("=").append(this.havingValue); } result.append(")"); return result.toString(); } }
根據(jù)業(yè)務(wù)需求,我們可以實(shí)現(xiàn)配置某些屬性動(dòng)態(tài)地去加載某些類或方法。
到此這篇關(guān)于SpringBoot之@ConditionalOnProperty注解使用方法的文章就介紹到這了,更多相關(guān)SpringBoot @ConditionalOnProperty注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中常見(jiàn)的日期操作(取值、轉(zhuǎn)換、加減、比較)
本文給大家介紹java中常見(jiàn)的日期操作,日期取值、日期轉(zhuǎn)換、日期加減、日期比較,對(duì)java日期操作相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-125分鐘搭建SpringCloud Eureka服務(wù)注冊(cè)中心的實(shí)現(xiàn)
這篇文章主要介紹了5分鐘搭建SpringCloud Eureka服務(wù)注冊(cè)中心的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03一文吃透消息隊(duì)列RocketMQ實(shí)現(xiàn)消費(fèi)冪等原理
這篇文章主要介紹了消息隊(duì)列RocketMQ實(shí)現(xiàn)消費(fèi)冪等的全面講解,幫助大家吃透RocketMQ消息隊(duì)列消費(fèi)冪等,更好的的應(yīng)用與工作實(shí)踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01在Java8與Java7中HashMap源碼實(shí)現(xiàn)的對(duì)比
這篇文章主要介紹了在Java8與Java7中HashMap源碼實(shí)現(xiàn)的對(duì)比,內(nèi)容包括HashMap 的原理簡(jiǎn)單介紹、結(jié)合源碼在Java7中是如何解決hash沖突的以及優(yōu)缺點(diǎn),結(jié)合源碼以及在Java8中如何解決hash沖突,balance tree相關(guān)源碼介紹,需要的朋友可以參考借鑒。2017-01-01Java對(duì)稱與非對(duì)稱加密算法原理詳細(xì)講解
對(duì)稱加密算法指加密和解密使用相同密鑰的加密算法。對(duì)稱加密算法用來(lái)對(duì)敏感數(shù)據(jù)等信息進(jìn)行加密,非對(duì)稱加密算法指加密和解密使用不同密鑰的加密算法,也稱為公私鑰加密2022-11-11spring MVC cors跨域?qū)崿F(xiàn)源碼解析
本文主要介紹了spring MVC cors跨域?qū)崿F(xiàn)源碼解析。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02