SpringBoot——@ConditionalOnProperty和@ConditionalOnProperty注解的详解和使用

news/2025/2/25 19:06:23

文章目录

  • 需求
  • @ConditionalOnProperty注解
    • 介绍
    • 源码解析
    • 使用示例
      • 新建bean类
      • 需测试的注解类
      • 配置场景一
      • 配置场景二
  • @ConditionalOnExpression
    • 介绍
    • 源码
    • 使用示例
      • 需测试的注解类一
      • 需测试的注解类二
      • 其他使用场景示例
  • 总结

需求

  在产品对接过程中,一个公共的服务对接多个产品,其中产品A使用RocketMQ进行消费,产品B无需消费。此时,代码共用了,如何做到产品B可以不消费?
  研究了一些方法,首先想到的是如何使RocketMQ的监听消费@RocketMQMessageListener注解失效。研究了一会儿,注解本身没有开关,也没有找到合适的方法去使指定注解失效。换了另一个方向:条件注解。亲测有效!

@ConditionalOnProperty注解

介绍

  1. SpringBoot中可以通过该注解来控制@Configuration是否生效。同时,我们可以通过该注解判断一个property属性,是否符合我们设定的配置值,符合则使该注解修饰的类或方法生效,否则不生效。
  2. 该注解是@Conditional的扩展注解。

源码解析

java">//
// 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类

java">@Data
public class PersonBean {
    /**
     * name
     */
    private String name;
    /**
     * age
     */
    private int age;
}

需测试的注解类

java">/**
 * @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

控制台日志结果

java">  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: 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

控制台日志结果

java">  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: 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

介绍

  1. 上述讲解的@ConditionalOnProperty只能精准的匹配havingValue中的值进行控制,无法根据更多的属性值进行匹配(即使它有数组的value值,也只能配合havingValue进行校验)
  2. 我们可以通过@ConditionalOnExpression注解进行其他属性值的表达式来校验。
  3. @ConditionalOnExpression是执行Spel表达式,根据返回的布尔值判断是否符合条件。

源码

java">//
// 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";
}

使用示例

需测试的注解类一

java">/**
 * @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值,此类都会生效。

需测试的注解类二

java">/**
 * @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.switchfalse值,此类才不会生效。

其他使用场景示例

  1. 布尔属性
java">@ConditionalOnExpression("${conditional.configuration.switch:true}
  1. 多个布尔属性,只要满足其一
java">@ConditionalOnExpression("${conditional.configuration.switch1:true} || ${conditional.configuration.switch2:true}")
  1. 配置值等于数字
java">@ConditionalOnExpression("${conditional.configuration.switch} == 1")
@ConditionalOnExpression("${conditional.configuration.switch} != 1")
  1. 配置值与指定字符串相同
java">@ConditionalOnExpression("'${conditional.configuration.switch}'.equals('yes')")
  1. 多个配置值相同
java">@ConditionalOnExpression("'${conditional.configuration.str1}'.equals('${conditional.configuration.str2}')")
  1. … …

总结

  本来只想用用@ConditionalOnProperty,用完@ConditionalOnExpression更爽一些!


http://www.niftyadmin.cn/n/233612.html

相关文章

50个linux常用命令【无废话版】

当您开始使用Linux操作系统时,以下是一些基本的命令可以帮助您更好地管理和操作系统。 目录 ls命令:列出当前目录中的文件和文件夹 cd命令:更改当前工作目录 pwd命令:显示当前工作目录的路径 mkdir命令:创建一个新…

ES6 生成器

基本概念 Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。 Generator函数有多种理解角度。从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。 执行Generator函数会返回…

IO多路转接—select,poll,epoll

目录 select 函数介绍 select基本工作流程 select的优缺点及适用场景 poll poll的优缺点 epoll epoll的相关系统调用 epoll_create epoll_ctl epoll_wait epoll工作原理 epoll服务器编写 epoll的优点 epoll工作方式 select 函数介绍 系统提供select函数来实现多路复…

Linux系统中curl命令用法

curl 是常用的命令行工具&#xff0c;用来请求 Web 服务器。它的名字就是客户端&#xff08;client&#xff09;的 URL 工具的意思。 常见参数&#xff1a; -A/--user-agent <string> 设置用户代理发送给服务器 -b/--cookie <namestring/file> c…

frp内网穿透——以连接到校园内网的服务器为例

有时候想摸鱼不去实验室&#xff0c;在宿舍就直接连接到实验室的GPU服务器。奈何服务器在校园网内部&#xff0c;外网无法直接直接访问。此时需要手动搭一个跳板机&#xff0c;来连接到内网的GPU服务器&#xff0c;这一过程怎么做到呢&#xff1f;我们可以使用frp内网穿透工具&…

Golang中是否可以无限开辟协程以及如何控制协程的数量?

文章目录1. Golang中是否可以无限开辟协程&#xff1f;2. 不控制goroutine数量引发的问题3. 如何控制goroutine的数量&#xff1f;⭐️3.1 只用有buffer的channel3.2 channel与sync同步组合方式3.3 利用无缓冲channel与任务发送/执行分离方式1. Golang中是否可以无限开辟协程&a…

ECShop开源商城与COS互通:降低本地存储负载、提升访问体验

ECShop简介 ECShop是一款开源电子商务平台&#xff0c;具有简单易用、安全稳定、模块化设计等特点。它提供了完整的电子商务解决方案&#xff0c;包括商品管理、订单管理、支付管理、配送管理、会员管理、促销管理、数据统计等功能。ECShop支持多语言、多货币、多种支付方式和配…

音频相关知识

目录 声音的本质 横波与纵波 为什么固体中既能传输横波&#xff0c;又能传输纵波&#xff0c;液体气体中只能传输纵波 声波 超声波与次声波 声音的三要素 音调 响度 音色 噪声 媒体音频 声道 分类 麦克风工作原理 模数转换 扬声器的使用原理 音频压缩类别 音…