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 編寫(xiě)加載類
編寫(xiě)加載類,使用@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ū)分大小寫(xiě)
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)文章
druid?handleException執(zhí)行流程源碼解析
這篇文章主要為大家介紹了druid?handleException執(zhí)行流程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
springboot2整合redis使用lettuce連接池的方法(解決lettuce連接池?zé)o效問(wèn)題)
這篇文章主要介紹了springboot2整合redis使用lettuce連接池(解決lettuce連接池?zé)o效問(wèn)題),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
SpringBoot使用RestTemplate發(fā)送http請(qǐng)求的實(shí)操演示
RestTemplate是Spring 框架提供的 ,可用于在應(yīng)用中調(diào)用 rest 服務(wù),它簡(jiǎn)化了與 http 服務(wù)的通信方式,統(tǒng)一了 RESTful 的標(biāo)準(zhǔn),封裝了 http 鏈接,本文給大家介紹了SpringBoot使用RestTemplate發(fā)送http請(qǐng)求的實(shí)操演示,需要的朋友可以參考下2024-11-11
Java中在控制臺(tái)讀取字符的實(shí)現(xiàn)示例
Scanner是Java中的一個(gè)類,可以用于讀取控制臺(tái)輸入,通過(guò)Scanner對(duì)象可以方便地從控制臺(tái)讀取數(shù)字或字符串,本文就來(lái)介紹一下Java中在控制臺(tái)讀取字符的實(shí)現(xiàn)示例,感興趣的可以了解一下2023-10-10

