
@ConditionalOn系列注解
对于@ConditionalOn系列注解而言
-
当添加在Java配置类(即被@Configuration注解修饰的类)上后,则只有符合期望条件后,才会对该Java配置类进行实例化 -
当添加在Java配置类中被@Bean注解修饰的方法上后,则只有符合期望条件后,才会调用该方法来创建相应的bean对象
常用地条件注解有:
-
@ConditionalOnClass注解:存在指定类时,才算符合条件 -
@ConditionalOnMissingClass注解:不存在指定类时,才算符合条件 -
@ConditionalOnBean注解:存在指定名称的bean时,才算符合条件 -
@ConditionalOnMissingBean注解:不存在指定名称的bean时,才算符合条件 -
@ConditionalOnProperty注解:其prefix属性用于指定检查的配置项的名称前缀;其name属性用于指定检查的配置项的名称;其havingValue属性用于指定配置项的期望值。具体地,如果配置项的值和该属性值相等,则条件成立;此外,当该属性配置为””空字符串,则意为相应配置项的值不为false时条件均成立;其matchIfMissing属性设置为true后,即使指定的配置项不存在,条件也会成立
测试:添加在类上
符合期望条件
这里我们将条件注解添加在Java配置类(即被@Configuration注解修饰的类)上,来测试符合期望条件的场景
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.context.annotation.Configuration;
// 该配置类会被实例化
@Configuration
public class MyConfig1 {
public MyConfig1() {
System.out.println("<My Config 1>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
// 存在指定类时,该配置类才会被实例化
@ConditionalOnClass(name = "com.aaron.application.SpringSpi.ConditionalOnTest.StuInfo")
@Configuration
public class MyConfig2 {
public MyConfig2() {
System.out.println("<My Config 2>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Configuration;
// 不存在指定类时,该配置类才会被实例化
@ConditionalOnMissingClass("com.aaron.application.SpringSpi.ConditionalOnTest.StuInfo123")
@Configuration
public class MyConfig3 {
public MyConfig3() {
System.out.println("<My Config 3>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
// 存在指定名称的bean时,该配置类才会被实例化
@ConditionalOnBean(name="stuInfo")
@Configuration
public class MyConfig4 {
public MyConfig4() {
System.out.println("<My Config 4>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Configuration;
// 不存在指定名称的bean时,该配置类才会被实例化
@ConditionalOnMissingBean(name="stuInfo123")
@Configuration
public class MyConfig5 {
public MyConfig5() {
System.out.println("<My Config 5>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
// 配置项 aaron.config.age 存在 且 配置值不为false 时,该配置类才会实例化
@ConditionalOnProperty(prefix = "aaron.config", name="age", havingValue = "", matchIfMissing = false)
@Configuration
public class MyConfig6 {
public MyConfig6() {
System.out.println("<My Config 6>: 被实例化");
}
}
同时为了测试各种条件,这里添加一个StuInfo类,同时添加了@Component注解。使其成为一个bean
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.stereotype.Component;
@Component
public class StuInfo {
}
此外为了测试@ConditionalOnProperty注解,在配置文件application.properties中添加下述配置
...
aaron.config.age=14
...
测试结果如下所示,符合预期

不符合期望条件
现在我们来修改下上述各条件注解上指定的条件,使其不符合期望条件
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.context.annotation.Configuration;
// 该配置类会被实例化
@Configuration
public class MyConfig1 {
public MyConfig1() {
System.out.println("<My Config 1>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
// 由于不存在 StuInfo123 类,故该配置类不会被实例化
@ConditionalOnClass(name = "com.aaron.application.SpringSpi.ConditionalOnTest.StuInfo123")
@Configuration
public class MyConfig2 {
public MyConfig2() {
System.out.println("<My Config 2>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Configuration;
// 由于存在 StuInfo 类,故该配置类不会被实例化
@ConditionalOnMissingClass("com.aaron.application.SpringSpi.ConditionalOnTest.StuInfo")
@Configuration
public class MyConfig3 {
public MyConfig3() {
System.out.println("<My Config 3>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
// 由于不存在 名为stuInfo123 的bean,故该配置类不会被实例化
@ConditionalOnBean(name="stuInfo123")
@Configuration
public class MyConfig4 {
public MyConfig4() {
System.out.println("<My Config 4>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Configuration;
// 由于存在 名为stuInfo 的bean,故该配置类不会被实例化
@ConditionalOnMissingBean(name="stuInfo")
@Configuration
public class MyConfig5 {
public MyConfig5() {
System.out.println("<My Config 5>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
// 由于配置项 aaron.config.age 的值不为996 时,故该配置类不会实例化
@ConditionalOnProperty(prefix = "aaron.config", name="age", havingValue = "996", matchIfMissing = false)
@Configuration
public class MyConfig6 {
public MyConfig6() {
System.out.println("<My Config 6>: 被实例化");
}
}
测试结果如下所示,符合预期

测试:添加在方法上
这里我们将条件注解添加在Java配置类中被@Bean注解修饰的方法上,来进行测试
package com.aaron.application.SpringSpi.ConditionalOnTest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig7 {
public MyConfig7() {
System.out.println("<My Config 7>: 被实例化");
}
// 存在指定类时,方法被调用,该bean才会被创建实例化
@ConditionalOnClass(name = "com.aaron.application.SpringSpi.ConditionalOnTest.StuInfo")
@Bean
public Object buildObjA() {
System.out.println("bean A 被创建、实例化");
return new Integer(2);
}
// 由于不存在 StuInfo123 类,方法不会被调用,故该bean不会被创建实例化
@ConditionalOnClass(name = "com.aaron.application.SpringSpi.ConditionalOnTest.StuInfo123")
@Bean
public Object buildObj() {
System.out.println("bean B 被创建、实例化");
return new Integer(7);
}
}
测试结果如下所示,符合预期

自定义条件注解
事实上,我们还可以通过@Conditional注解来自定义条件注解。具体地,只需给@Conditional注解的value属性设置自定义规则的某个类即可。对于该自定义类而言,需实现Condition接口的matches方法来自定义规则。当该方法返回true为符合期望条件;返回false为不符合期望条件
这里我们想自定义一个条件注解:通过配置项的值是否位于指定区间,来判定是否符合期望条件。我们可以定义一个组合注解@ConditionalOnPropertyRange。其一方面拥有自定义的name、min、max属性;另一方面,在该注解上添加了@Conditional注解,同时指定相应的规则类为OnPropertyRangeCondition
package com.aaron.application.SpringSpi.CustomConditionalTest;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnPropertyRangeCondition.class)
public @interface ConditionalOnPropertyRange {
String name() default "";
int min() default -1;
int max() default -1;
}
这里相应的规则类OnPropertyRangeCondition实现如下所示
package com.aaron.application.SpringSpi.CustomConditionalTest;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnPropertyRangeCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取 ConditionalOnPropertyRange 注解上的参数值
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnPropertyRange.class.getName());
if (annotationAttributes == null || annotationAttributes.isEmpty()) {
return false;
}
String propertyName = (String)annotationAttributes.get("name");
int min = (int) annotationAttributes.get("min");
int max = (int) annotationAttributes.get("max");
// 获取指定配置项的值
Integer propertyValue = context.getEnvironment().getProperty(propertyName, Integer.class);
if( propertyValue==null || propertyValue<min || propertyValue>max ) {
// 条件不通过
return false;
}
// 条件通过
return true;
}
}
现在我们来提供两个配置类,验证我们自定义的条件注解@ConditionalOnPropertyRange
package com.aaron.application.SpringSpi.CustomConditionalTest;
import org.springframework.context.annotation.Configuration;
// 配置项aaron.config.weight的值在[min,max]范围区间内,故该配置类会被实例化
@ConditionalOnPropertyRange(name="aaron.config.weight", min=50, max=60)
@Configuration
public class MyConfig8 {
public MyConfig8() {
System.out.println("<My Config 8>: 被实例化");
}
}
...
package com.aaron.application.SpringSpi.CustomConditionalTest;
import org.springframework.context.annotation.Configuration;
// 配置项aaron.config.weight的值不在[min,max]范围区间内,故该配置类不会被实例化
@ConditionalOnPropertyRange(name="aaron.config.weight", min=250, max=260)
@Configuration
public class MyConfig9 {
public MyConfig9() {
System.out.println("<My Config 9>: 被实例化");
}
}
同时,在配置文件application.properties中添加下述配置
...
aaron.config.weight=55
...
测试结果如下所示,符合预期

原文始发于微信公众号(青灯抽丝):SpringBoot之条件注解
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/241166.html