目录
1) @ConditionalOnClass和@ConditionalOnMissingClass注解
2) @ConditionalOnBean 和@ConditionalOnMissingBean注解
@Conditional注解是Spring-context模块提供了一个注解,该注解的作用是可以根据一定的条件来使@Configuration注解标记的配置类是否生效,代码如下:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
-
- package org.springframework.context.annotation;
-
- 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;
-
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface Conditional {
- Class extends Condition>[] value();
- }
value值为实现Condition 接口的一个Class,Spring框架根据实现Conditon接口的matches方法返回true或者false来做以下操作,如果matches方法返回true,那么该配置类会被Spring扫描到容器里, 如果为false,那么Spring框架会自动跳过该配置类不进行扫描装配,使用方法:
实现Condition接口, 例如在配置文件里配置了dataSource.none=true, 那么表示不需要使用数据源,那么Spring在扫描的时候会自动跳过该配置类。
- package com.bing.sh.datasource;
-
- import org.springframework.context.annotation.Condition;
- import org.springframework.context.annotation.ConditionContext;
- import org.springframework.core.type.AnnotatedTypeMetadata;
-
- /**
- * 如果为返回false,那么Spring会忽略配置类
- */
- public class DataSourceCondition implements Condition {
-
-
- @Override
- public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
- // 此处使用 conditionContext获取Environment即可。
- String configureDataSource = conditionContext.getEnvironment().getProperty("dataSource.none", "false");
- return "false".equals(configureDataSource);
- }
-
-
- }
定义配置类,与@Conditional注解一起使用:
- @Configuration
- @Conditional(value = DataSourceCondition.class)
- public class CustomDataSourceConfig {
-
-
- }
除了Conditional注解,Spring boot 框架提供了 其他conditional系列注解。
SpringBoot的spring-boot-autoconfigure模块也提供了Conditional系列的相关注解,这些注解能帮助开发者根据一定的条件去装载需要的Bean。

当Spring加载的Bean被@ConditionOnClass注解标记时,类加载器会先去先找到指定的Class, 如果没有找到目标Class,那么被ConditionOnClass注解标记的类不会被Spring装载,相反ConditionalOnMissingBean是指如果没有找到目标Class, 那么就装载该类。
当Spring加载的Bean被@ConditionalOnBean注解标记时,接下来会先找到指定的Bean,如果没有找到目标Bean,那么被@ConditionalOnBean标记的类不会被Spring装载,相反ConditionalOnMissingBean是指如果没有Class, 那么就装载该Bean。
看一个例子, Dubbo与Springboot做自动装配时,先寻找BASE_PACKAGES_BEAN_NAME这个Bean, 如果Bean 不存在,那么serviceAnnotationBeanProcessor这个Bean不会被Spring 装载.
- @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
- @Configuration
- @AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
- @EnableConfigurationProperties(DubboConfigurationProperties.class)
- @EnableDubboConfig
- public class DubboAutoConfiguration {
-
- /**
- * Creates {@link ServiceAnnotationPostProcessor} Bean
- * dubbo.scan.base-packages
- * @param packagesToScan the packages to scan
- * @return {@link ServiceAnnotationPostProcessor}
- */
- @ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
- // 先找BASE_PACKAGES_BEAN_NAME 这个bean, 如果没有这个bean, 那么serviceAnnotationBeanProcessor不会被Spring装载。
- @ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
- @Bean
- public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
- Set
packagesToScan) { - return new ServiceAnnotationPostProcessor(packagesToScan);
- }
-
- }
使用@ConditionalOnMissingBean注解定义BASE_PACKAGES_BEAN_NAME这个Bean
- /**
- * Dubbo Relaxed Binding Auto-{@link Configuration} for Spring Boot 2.0
- *
- * @see DubboRelaxedBindingAutoConfiguration
- * @since 2.7.0
- */
- @Configuration
- @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
- @ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
- @AutoConfigureBefore(DubboRelaxedBindingAutoConfiguration.class)
- public class DubboRelaxedBinding2AutoConfiguration {
-
- public PropertyResolver dubboScanBasePackagesPropertyResolver(ConfigurableEnvironment environment) {
- ConfigurableEnvironment propertyResolver = new AbstractEnvironment() {
- @Override
- protected void customizePropertySources(MutablePropertySources propertySources) {
- Map
dubboScanProperties = getSubProperties(environment.getPropertySources(), DUBBO_SCAN_PREFIX); - propertySources.addLast(new MapPropertySource("dubboScanProperties", dubboScanProperties));
- }
- };
- ConfigurationPropertySources.attach(propertyResolver);
- return propertyResolver;
- }
-
- /**
- * The bean is used to scan the packages of Dubbo Service classes
- * 如果没有就创建
- * @param environment {@link Environment} instance
- * @return non-null {@link Set}
- * @since 2.7.8
- */
- @ConditionalOnMissingBean(name = BASE_PACKAGES_BEAN_NAME)
- @Bean(name = BASE_PACKAGES_BEAN_NAME)
- public Set
dubboBasePackages(ConfigurableEnvironment environment) { - PropertyResolver propertyResolver = dubboScanBasePackagesPropertyResolver(environment);
- return propertyResolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
- }
-
- @ConditionalOnMissingBean(name = RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME, value = ConfigurationBeanBinder.class)
- @Bean(RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME)
- @Scope(scopeName = SCOPE_PROTOTYPE)
- public ConfigurationBeanBinder relaxedDubboConfigBinder() {
- return new BinderDubboConfigBinder();
- }
-
- }
该注解的作用是解析application.yml/application.properties 里的配置生成条件来生效,也是与@Configuration注解一起使用。
| 属性 | 功能 | 其他 |
| prefix | 读取配置里的前缀值为prefix的属性, 如果没有返回false | |
| name | 读取属性配置里的Key值,如果配置了prefix,那么需要先拼接prefix然后匹配havingValue值 | |
| havingValue | 匹配属性里的值 | |
| matchIfMissing | 当未找到对应的配置时是否匹配,默认为false, 如果为true,没有找到配置,那么也匹配。 |
使用场景,例如在指定数据源时,指定datasource的type。例如包含如下配置使用Hikari数据源。
spring.datasource.type=com.zaxxer.hikari.HikariDataSource

在使用时,一般设置matchIfMissing=false, 这样条件没有匹配上的话会Spring在扫描bean时会自动跳过该配置类。
也可以设定matchIfMissing=true,这种场景例如缓存,我们可以这样配置默认是开启缓存的。
- @ConditionalOnProperty(name={cache.effect},marchIfMissing=true)
-
- public class CacheAutoConfiguration{
-
-
-
- // ...
-
- }
如果在application.properties里配置cache.effect=false, 那么该配置类就会跳过,这样配置就能使缓存不生效。