您现在的位置是:首页 >其他 >SpringBoot——@ConditionalOnProperty和@ConditionalOnProperty注解的详解和使用网站首页其他
SpringBoot——@ConditionalOnProperty和@ConditionalOnProperty注解的详解和使用
简介SpringBoot——@ConditionalOnProperty和@ConditionalOnProperty注解的详解和使用
文章目录
需求
在产品对接过程中,一个公共的服务对接多个产品,其中产品A使用RocketMQ
进行消费,产品B无需消费。此时,代码共用了,如何做到产品B可以不消费?
研究了一些方法,首先想到的是如何使RocketMQ
的监听消费@RocketMQMessageListener
注解失效。研究了一会儿,注解本身没有开关,也没有找到合适的方法去使指定注解失效。换了另一个方向:条件注解。亲测有效!
@ConditionalOnProperty注解
介绍
- 在
SpringBoot
中可以通过该注解来控制@Configuration
是否生效。同时,我们可以通过该注解判断一个property属性,是否符合我们设定的配置值,符合则使该注解修饰的类或方法生效,否则不生效。 - 该注解是
@Conditional
的扩展注解。
源码解析
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.autoconfigure.condition;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnPropertyCondition.class})
public @interface ConditionalOnProperty {
//数组,获取property对应的值,与name属性不可以同时使用
String[] value() default {};
//属性名称值的前缀
String prefix() default "";
//数组,配置属性值的名称,可与prefix组合使用,不可与value属性同时使用
String[] name() default {};
//比较和name属性值获取到的属性值是否相同,与name组合使用,若true,则加载配置
String havingValue() default "";
//缺少配置是否匹配加载,若为true,则表示无该name相关属性值,也加载。反之,不加载。
boolean matchIfMissing() default false;
}
使用示例
新建bean类
@Data
public class PersonBean {
/**
* name
*/
private String name;
/**
* age
*/
private int age;
}
需测试的注解类
/**
* @Description 测试bean配置
* @Author LiaoJy
* @Date 2023/4/17
*/
@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "conditional", name = "configuration.switch", havingValue = "true", matchIfMissing = true)
public class BeanConfigTest {
@Bean
public PersonBean personBean() {
PersonBean personBean = new PersonBean();
personBean.setAge(30);
personBean.setName("andya");
log.info("========person bean init========");
return personBean;
}
}
配置场景一
conditional:
configuration:
switch: false
控制台日志结果
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )\___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.9)
... ...
2023-04-17 14:14:11.620 INFO 25494 --- [ main] c.test.selfcoding.SelfCodingApplication : No active profile set, falling back to 1 default profile: "default"
2023-04-17 14:14:12.175 INFO 25494 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8001 (http)
2023-04-17 14:14:12.182 INFO 25494 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-04-17 14:14:12.182 INFO 25494 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.64]
2023-04-17 14:14:12.259 INFO 25494 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-04-17 14:14:12.259 INFO 25494 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 609 ms
2023-04-17 14:14:12.445 INFO 25494 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8001 (http) with context path ''
2023-04-17 14:14:12.451 INFO 25494 --- [ main] c.test.selfcoding.SelfCodingApplication : Started SelfCodingApplication in 1.123 seconds (JVM running for 1.387)
结果未打印========person bean init========
日志,类未生效。
配置场景二
不配置,或者配置如下
conditional:
configuration:
switch: true
控制台日志结果
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _
( ( )\___ | '_ | '_| | '_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.9)
... ...
2023-04-17 14:17:35.172 INFO 25577 --- [ main] c.test.selfcoding.SelfCodingApplication : No active profile set, falling back to 1 default profile: "default"
2023-04-17 14:17:35.771 INFO 25577 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8001 (http)
2023-04-17 14:17:35.777 INFO 25577 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-04-17 14:17:35.777 INFO 25577 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.64]
2023-04-17 14:17:35.859 INFO 25577 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-04-17 14:17:35.859 INFO 25577 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 655 ms
2023-04-17 14:17:35.899 INFO 25577 --- [ main] c.test.selfcoding.config.BeanConfigTest : ========person bean init========
2023-04-17 14:17:36.134 INFO 25577 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8001 (http) with context path ''
2023-04-17 14:17:36.141 INFO 25577 --- [ main] c.test.selfcoding.SelfCodingApplication : Started SelfCodingApplication in 1.421 seconds (JVM running for 1.775)
可以看到打印了========person bean init========
日志,类生效。
@ConditionalOnExpression
介绍
- 上述讲解的
@ConditionalOnProperty
只能精准的匹配havingValue
中的值进行控制,无法根据更多的属性值进行匹配(即使它有数组的value
值,也只能配合havingValue
进行与
校验) - 我们可以通过
@ConditionalOnExpression
注解进行其他属性值的表达式来校验。 @ConditionalOnExpression
是执行Spel
表达式,根据返回的布尔值判断是否符合条件。
源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.autoconfigure.condition;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnExpressionCondition.class})
public @interface ConditionalOnExpression {
//Spel表达式
String value() default "true";
}
使用示例
需测试的注解类一
/**
* @Description 测试bean配置
* @Author LiaoJy
* @Date 2023/4/17
*/
@Slf4j
@Configuration
//@ConditionalOnProperty(prefix = "conditional", name = "configuration.switch", havingValue = "true", matchIfMissing = true)
@ConditionalOnExpression("!'${conditional.configuration.switch}'.equals('false')")
public class BeanConfigTest {
@Bean
public PersonBean personBean() {
PersonBean personBean = new PersonBean();
personBean.setAge(30);
personBean.setName("andya");
log.info("========person bean init========");
return personBean;
}
}
此时只要配置conditional.configuration.switch
不为false
值,此类都会生效。
需测试的注解类二
/**
* @Description 测试bean配置
* @Author LiaoJy
* @Date 2023/4/17
*/
@Slf4j
@Configuration
//@ConditionalOnProperty(prefix = "conditional", name = "configuration.switch", havingValue = "true", matchIfMissing = true)
@ConditionalOnExpression("${conditional.configuration.switch:true}")
public class BeanConfigTest {
@Bean
public PersonBean personBean() {
PersonBean personBean = new PersonBean();
personBean.setAge(30);
personBean.setName("andya");
log.info("========person bean init========");
return personBean;
}
}
此时只有配置conditional.configuration.switch
为false
值,此类才不会生效。
其他使用场景示例
- 布尔属性
@ConditionalOnExpression("${conditional.configuration.switch:true}
- 多个布尔属性,只要满足其一
@ConditionalOnExpression("${conditional.configuration.switch1:true} || ${conditional.configuration.switch2:true}")
- 配置值等于数字
@ConditionalOnExpression("${conditional.configuration.switch} == 1")
@ConditionalOnExpression("${conditional.configuration.switch} != 1")
- 配置值与指定字符串相同
@ConditionalOnExpression("'${conditional.configuration.switch}'.equals('yes')")
- 多个配置值相同
@ConditionalOnExpression("'${conditional.configuration.str1}'.equals('${conditional.configuration.str2}')")
- … …
总结
本来只想用用@ConditionalOnProperty
,用完@ConditionalOnExpression
更爽一些!
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。