SpringBoot中提供了一系列的条件注解(@Conditional
)来实现对@Bean
和@Configuration
等实例的创建进行约束。这些注解包括:
Class Conditions
,类条件约束Bean Conditions
,Bean条件约束Property Conditions
,配置项条件约束Resource Conditions
,文件条件约束Web Application Conditions
,Web应用条件约束SpEL Expression Conditions
,SpEL表达式条件约束
类条件约束
类条件注解有两个:@ConditionalOnClass
和@ConditionalOnMissingClass
。
类条件注解通常用于自动化配置管理中,作用是根据某个(或某些)类的存在与否来决定一个@Configuration
注解的类是否需要被解析并注入。
因为自动化配置类是在一个独立的jar包中,而且SpringBoot是使用ASM执行类条件注解的解析,也就是说相关的@Configuration
类不一定会被加载,所以@ConditionalOnClass
和@ConditionalOnMissingClass
的value属性可以是一个类。
当然,如果存在顾虑的话,也可以使用全限定类名字符串设置name属性的值。尤其是在应用内部使用类条件约束注解的时候,就只能使用name属性了。
当类条件约束注解用于@Bean
注解的方法时存在一种特殊的情形:即约束注解的value值就是方法的返回值的类型。因为在注解生效前,JVM就已经加载了这个类并开始尝试处理方法的引用,此时如果相关的类不存在就会执行失败。
为了解决这种问题,可以将一个@Configuration
类拆分开来,如下例所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Configuration(proxyBeanMethods = false) // Some conditions public class MyAutoConfiguration { // Auto-configured beans @Configuration(proxyBeanMethods = false) @ConditionalOnClass(EmbeddedAcmeService.class) static class EmbeddedConfiguration { @Bean @ConditionalOnMissingBean public EmbeddedAcmeService embeddedAcmeService() {...} } } |
类条件约束注解会影响@Configuration
类的创建。
Bean条件约束
Bean条件注解也有两个:@ConditionalOnBean
和@ConditionalOnMissingBean
,作用是根据当前容器中是否存在指定的Bean来决定是否进行注入。
可以使用注解的value属性来按类指定Bean,也可以使用name属性按名称指定Bean。search属性可以用来限制在容器的哪些层级上搜索Bean。
当把Bean条件约束注解用于@Bean
方法上时,type属性的值默认就是方法返回值的类型,看个例子:
1 2 3 4 5 6 7 8 |
@Configuration(proxyBeanMethods = false) public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService() { ... } } |
如上面的示例代码:如果如果容器中目前没有MyService
类的实例,这里就会创建一个myService 实例并注入。
因为是根据当前已经加载过的类进行判断的,所以在使用Bean条件约束注解时,需要注意相关Bean的加载次序。
在自动化配置类中使用时,则无需考虑这些事情,因为自动化配置类中的Bean一定会在用户自定义的Bean都注入完成后才会被加载。
@ConditionalOnBean
和@ConditionalOnMissingBean
并不会阻止@Configuration
类的创建,只会对@Configuration
类实例的注入产生影响。
配置项条件约束
配置项条件注解@ConditionalOnProperty
会根据SpringEnvironment的属性(或者说是配置信息)进行约束。
使用注解的prefix和name属性可以指定要检查的配置项。
可以根据havingValue和matchIfMissing属性来设置配置项的预期值。
如果不做任何设置的话,只要配置项的值存在且不为false就一定能通过校验。
另外,如果将配置视为是树结构的话,那么指定的配置项一定是叶子结点,如下例:
1 2 3 4 5 6 7 8 |
kafka: common: bootstrap_servers: kafka25:9092,kafka26:9092,kafka27:9092 consumers: - group_id: test-group topics: [test-topic1,test-topic2] processor: org.chobit.spring.component.MyProcessor count: 3 |
如果指定的配置项是kafka.common或kafka.consumers,校验的返回结果一定是false,只有指定kafka.common.bootstrap_servers或kafka.consumers[0].topics才有意义。
资源条件约束
资源条件注解@ConditionalOnResource
会根据指定的资源文件是否存在来进行校验。资源文件名如:file:/home/user/test.dat。
Web应用条件约束
Web应用条件注解同样有两个:@ConditionalOnWebApplication
和@ConditionalOnNotWebApplication
。
这类注解会校验当前应用是否是web应用。
如当前应用是一个servlet类型的web应用,那么判断依据就会是是否存在WebApplicationContext
容器,有没有定义session scope,或者是否存在ConfigurableWebEnvironment
实例。
而react类型的的web应用判断依据则是是否有使用ReactiveWebApplicationContext
容器,或者是否存在ConfigurableReactiveWebEnvironment
实例。
SpEL表达式条件约束
SpEL表达式条件注解@ConditionalOnExpression
会根据SpEL表达式进行校验。
关于SpEL表达式可以参考前文《使用SpEL表达式》。
End!
发表评论