Spring boot中的注解@ConditionalOnProperty,可以通过配置文件中的属性值来判定configuration是否被注入.
配置类:
@Configuration
@ConditionalOnProperty(prefix = “x.y”, name = “test”, havingValue = “1”, matchIfMissing = true)
public class XConfiguration {…}
配置文件:
x.y.test=1
解释:
prefix为配置文件中的前缀.
name为配置的名字.
havingValue是与配置的值对比值,当两个值相同返回true,配置类生效.
matchIfMissing属性为true时,配置文件中缺少对应的value或name的对应的属性值,也会注入成功.
使用场景:
1、在日常使用中,定义一个mq的消费,在本地测试环境、预发环境、线上环境均对此定义,满足不同阶段的开发、测试、上线需要。通常接入一个新的mq消费,三个环境使用同一套mq配置,可以保障开发联调效率和上线后保证和预发环境一致。但在一个mq主题中,一个应用只能消费一次,就意味着三个环境同时运行,只能有一个环境生效,则可以使用 @ConditionalOnProperty 注解,通过配置控制。
2、过滤器等随部署环境变动的类,使用该注解方便调试。
@ConditionalOnProperty(
prefix = "zn.com.interceptor",
name = "enable",
havingValue = "true"
)
还可以用在链式配置中,比如Spring MVC的过滤器和拦截器。
3、通过@ConditionalOnProperty来控制Configuration是否生效
@Configuration
//在application.properties配置"mf.assert",对应的值为true
@ConditionalOnProperty(prefix="mf",name = "assert", havingValue = "true")
public class AssertConfig {
@Autowired
private HelloServiceProperties helloServiceProperties;
@Bean
public HelloService helloService(){
HelloService helloService = new HelloService();
helloService.setMsg(helloServiceProperties.getMsg());
return helloService;
}
}
=====================
需要自己实现match方法
可以通过属性配置值,通过配置实现,更灵活方便,不用写代码
附1:类似的有很多
@Conditional(ZiDingYiCondition.class)
@ConditionalOnProperty
@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnResource
@ConditionalOnExpression
@ConditionalOnMissingBean
其中:
public class ZiDingYiCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = context.getEnvironment();
String activeProfiles = environment.getActiveProfiles()[0];
return "online".equals(activeProfiles);
}
}
附2:ConditionalOnProperty的定义,可以理解为通过值控制校验 条件。
/**
* {@link Conditional} that checks if the specified properties have a specific value. By
* default the properties must be present in the {@link Environment} and
* not equal to {@code false}. The {@link #havingValue()} and
* {@link #matchIfMissing()} attributes allow further customizations.
*
* The {@link #havingValue} attribute can be used to specify the value that the property
* should have. The table below shows when a condition matches according to the property
* value and the {@link #havingValue()} attribute:
*
*
*
* Having values
*
* Property Value
* {@code havingValue=""}
* {@code havingValue="true"}
* {@code havingValue="false"}
* {@code havingValue="foo"}
*
*
* {@code "true"}
* yes
* yes
* no
* no
*
*
* {@code "false"}
* no
* no
* yes
* no
*
*
* {@code "foo"}
* yes
* no
* no
* yes
*
*
*
* If the property is not contained in the {@link Environment} at all, the
* {@link #matchIfMissing()} attribute is consulted. By default missing attributes do not
* match.
*
* This condition cannot be reliably used for matching collection properties. For example,
* in the following configuration, the condition matches if {@code spring.example.values}
* is present in the {@link Environment} but does not match if
* {@code spring.example.values[0]} is present.
*
*
* @ConditionalOnProperty(prefix = "spring", name = "example.values")
* class ExampleAutoConfiguration {
* }
*
*
* It is better to use a custom condition for such cases.
*
* @author Maciej Walkowiak
* @author Stephane Nicoll
* @author Phillip Webb
* @since 1.1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
/**
* Alias for {@link #name()}.
* @return the names
*/
String[] value() default {};
/**
* A prefix that should be applied to each property. The prefix automatically ends
* with a dot if not specified. A valid prefix is defined by one or more words
* separated with dots (e.g. {@code "acme.system.feature"}).
* @return the prefix
*/
String prefix() default "";
/**
* The name of the properties to test. If a prefix has been defined, it is applied to
* compute the full key of each property. For instance if the prefix is
* {@code app.config} and one value is {@code my-value}, the full key would be
* {@code app.config.my-value}
*
* Use the dashed notation to specify each property, that is all lower case with a "-"
* to separate words (e.g. {@code my-long-property}).
* @return the names
*/
String[] name() default {};
/**
* The string representation of the expected value for the properties. If not
* specified, the property must not be equal to {@code false}.
* @return the expected value
*/
String havingValue() default "";
/**
* Specify if the condition should match if the property is not set. Defaults to
* {@code false}.
* @return if should match if the property is missing
*/
boolean matchIfMissing() default false;
}
其中:
/**
* {@link Condition} that checks if properties are defined in environment.
*
* @author Maciej Walkowiak
* @author Phillip Webb
* @author Stephane Nicoll
* @author Andy Wilkinson
* @since 1.1.0
* @see ConditionalOnProperty
*/
@Order(Ordered.HIGHEST_PRECEDENCE + 40)
class OnPropertyCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
List<ConditionMessage> noMatch = new ArrayList<>();
List<ConditionMessage> match = new ArrayList<>();
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment());
(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
}
if (!noMatch.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
}
return ConditionOutcome.match(ConditionMessage.of(match));
}
//略
}