重视微信公众号:CodingTechWork,一同学习前进。

需求

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

@ConditionalOnProperty注解

介绍

  1. SpringBoot中能够经过该注解来控制@Configuration是否收效。一起,咱们能够经过该注解判别一个property特点,是否契合咱们设定的装备值,契合则使该注解修饰的类或方法收效,否则不收效。
  2. 该注解是@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

介绍

  1. 上述讲解的@ConditionalOnProperty只能精准的匹配havingValue中的值进行控制,无法依据更多的特点值进行匹配(即使它有数组的value值,也只能配合havingValue进行校验)
  2. 咱们能够经过@ConditionalOnExpression注解进行其他特点值的表达式来校验。
  3. @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.switchfalse值,此类才不会收效。

其他运用场景示例

  1. 布尔特点
@ConditionalOnExpression("${conditional.configuration.switch:true}
  1. 多个布尔特点,只需满意其一
@ConditionalOnExpression("${conditional.configuration.switch1:true} || ${conditional.configuration.switch2:true}")
  1. 装备值等于数字
@ConditionalOnExpression("${conditional.configuration.switch} == 1")
@ConditionalOnExpression("${conditional.configuration.switch} != 1")
  1. 装备值与指定字符串相同
@ConditionalOnExpression("'${conditional.configuration.switch}'.equals('yes')")
  1. 多个装备值相同
@ConditionalOnExpression("'${conditional.configuration.str1}'.equals('${conditional.configuration.str2}')")
  1. … …

总结

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