简概
您几乎总是希望在自动配置类中包含一个或多个@Conditional
注解。@ConditionalOnMissingBean
注解是一个常见的例子,用于允许开发人员在不满意您的默认值时覆盖自动配置。
Spring Boot包含许多@Conditional
注解,您可以在自己的代码(注解@Configuration
的类或单独的@Bean
方法)上重用这些注解。这些注解包括:
- Class Conditions
- Bean Conditions
- Property Conditions
- Resource Conditions
- Web Application Conditions
- SpEL Expression Conditions
Class Conditions
@ConditionalOnClass
和@ConditionalOnMissingClass
注解允许根据特定类的存在或不存在来决定是否包含@Configuration
类。由于注解元数据是通过使用ASM解析的,所以可以使用value
属性来引用真正的类,即使这个类实际上可能不会出现在正在运行的应用程序类路径上。如果您希望通过使用String值指定类名,也可以使用name
属性。
这种机制并不以同样的方式应用于@Bean
方法,在@Bean
方法中,通常返回类型是条件的目标:在方法上的条件应用之前,JVM将加载类和潜在处理的方法引用,如果类不存在,这些方法引用将失败。【一个可参考点:https://cloud.tencent.com/developer/article/1449288】
要处理这种情况,可以使用一个单独的@Configuration
类来隔离条件,如下面的示例所示:
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@AutoConfiguration
// Some conditions ...
public class MyAutoConfiguration {
// Auto-configured beans ...
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SomeService.class)
public static class SomeServiceConfiguration {
@Bean
@ConditionalOnMissingBean
public SomeService someService() {
return new SomeService();
}
}
}
如果使用@ConditionalOnClass
或@ConditionalOnMissingClass
作为元注解的一部分来组成自己的合成注解,在这种情况没有被处理时,必须使用name来引用类。
Bean Conditions
@ConditionalOnBean
和@ConditionalOnMissingBean
注解允许根据特定bean的存在或不存在来决定是否包含bean。您可以使用value
属性按type或name指定bean。search
属性允许您限制在搜索bean时应该考虑的ApplicationContext
层次结构。
当放在@Bean方法上时,目标类型默认为方法的返回类型,如下例所示:
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
@AutoConfiguration
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SomeService someService() {
return new SomeService();
}
}
在上面的示例中,如果ApplicationContext
中没有包含someService
类型的bean,则将创建someService
bean。
需要特别注意添加bean定义的顺序,因为这些条件是根据到目前为止所处理的内容来计算的。由于这个原因,我们建议只在自动配置类上使用@ConditionalOnBean
和@ConditionalOnMissingBean
注解(因为这能保证在添加任何用户定义的bean definitions
后再加载这些注解)。
@ConditionalOnBean
和@ConditionalOnMissingBean
不阻止@Configuration
类的创建。在类级别使用这些条件与用注解标记其中包含的@Bean方法之间的唯一区别是,如果条件不匹配,前者会阻止将@Configuration
类注册为bean
在声明@Bean
方法时,在方法的返回类型中提供尽可能多的类型信息。例如,如果bean的具体类实现了一个接口,那么bean方法的返回类型应该是具体类而不是接口。在使用bean conditions
时,在@Bean方法中提供尽可能多的类型信息尤其重要,因为它们的计算只能依赖于方法签名中可用的类型信息。
Property Conditions
@ConditionalOnProperty
注解允许基于Spring Environment property
来决定是否配置。使用前缀和名称属性指定应该检查的属性。缺省情况下,匹配任何存在且不等于false的属性。还可以通过使用havingValue
和matchIfMissing
属性创建更高级的检查。
Web Application Conditions
@ConditionalOnWebApplication
和@ConditionalOnNotWebApplication
注解允许根据应用程序是否是一个“web application”来决定是否配置。基于servlet的web应用程序是任何使用Spring WebApplicationContext
、定义了session scope
或具有ConfigurableWebEnvironment
的应用程序。响应式web应用程序是任何使用ReactiveWebApplicationContext
或ConfigurableReactiveWebEnvironment
的应用程序。
@ConditionalOnWarDeployment
注解允许根据应用程序是否是部署到容器的传统WAR应用程序来决定是否包含配置。此条件不适用于使用嵌入式服务器运行的应用程序。
SpEL Expression Conditions
@ConditionalOnExpression注解允许根据SpEL expression的结果决定是否包含配置。
在表达式中引用bean将导致在上下文刷新处理中很早就初始化该bean。因此,bean将不能进行后处理(例如配置属性绑定),并且它的状态可能是不完整的