記事ディレクトリ
必要
製品ドッキングのプロセスでは、パブリック サービスが複数の製品を接続します。製品 A はRocketMQ
消費に使用され、製品 B は消費する必要がありません。この時点でコードは共有されていますが、製品 B を消費しないようにするにはどうすればよいでしょうか?
いくつかの方法を検討した後、最初に思い浮かぶのは、RocketMQ
監視消費@RocketMQMessageListener
アノテーションを無効にする方法です。しばらく調べてみましたが、アノテーション自体にスイッチがなく、指定されたアノテーションを無効にする適切な方法が見つかりませんでした。別の方向: 条件付きアノテーション。プロテストは効果あり!
@ConditionalOnProperty アノテーション
導入
- では
SpringBoot
、この注釈を使用して、それが有効になるかどうかを制御できます@Configuration
。同時に、このアノテーションを使用して、プロパティの属性が設定した設定値に適合しているかどうかを判断することができ、一致する場合はアノテーションによって変更されたクラスまたはメソッドが有効になり、そうでない場合は有効になりません。 - このアノテーション
@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;
}
}
構成シナリオ 1
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========
、クラスは有効になりません。
構成シナリオ 2
設定しない、または次のように設定します
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
テストされるアノテーション クラス 2
/**
* @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}
- 複数のブール型プロパティ (いずれか 1 つが満たされている場合)
@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