Spring学习之@Conditional
文章目录
注解说明
@Conditional 是 Spring 提供的用于判断是否对 Bean 注入的条件注解(在4.0后版本引入),只有满足了所有的条件,一个 bean 才会被注册成功并使用。此注解可标注在类上、元注解上、@Bean方法上,通常与 @Configuration 注解配合使用,标识在 @Configuration 注解上的 @Conditional 会影响此配置类的所有 @Bean 注解方法、@Import 注解和@ComponentScan 注解。另需注意 @Conditional 注解不支持继承
对于标注在元注解上的样例,可查看 SpringBoot 项目下的
org.springframework.boot.autoconfigure.condition
包以 ConditionalOn 开头的类
注解属性
此注解只有一个属性 value
,返回类型为 Class 数组,它用来配置所有的 Condition 类信息

Condition 是 Spring 提供的一个接口,它提供了 matches 方法来提供判断的依据逻辑,对于其参数 ConditionContext 提供了丰富的上下文信息
测试代码
|
|
源码阅读
对于 Configuration 类条件处理分为两个阶段:
- PARSE_CONFIGURATION, 解析 @Configuration 类阶段
- REGISTER_BEAN,注册Bean阶段,如 @Configuration 类下定义的 @Bean 方法
快速解析Configuration注解类
快速解析 @Conditional 注解的逻辑在 AnnotationConfigApplicationContext的register阶段,此方法会调用 AnnotatedBeanDefinitionReader#doRegisterBean
来对Spring中常用的组件类(@Compnent,@Configuration)进行注入操作,在此方法会调用核心方法 ConditionEvaluator#shouldSkip
来判断要处理类的是否要进行注册。 shouldSkip 会先判断是否标注有 @Conditional 注解,如果没有则进行正常的注册,如果有则会调用 collectConditions()
方法收集注解上的 Condition 信息并进行排序返回(此操作会先从配置类上获取 Condition 类信息再实例化类),然后会遍历 conditions 来进行判断,如果调用某个 Condition的match() 方法返回 false
,则确认此配置类的解析需要跳过


由于测试代码的 MyConfiguration 注解类没有标注 @Conditional 相关的注解,则此类中的其它配置在后续 refresh 阶段会继续进行解析
解析其它配置及配置中的Bean
除了在 AnnotationConfigApplicationContext
的构造方法中提供的配置类解析后,其它的配置类及其类中的配置条件判断都发生在 refresh
阶段,这里面的判断逻辑发生在 @Configuration 配置的解析流程中,主要涉及 @Configuration、@Componenet、@Import、@Bean 这4个注解的解析
解析@Configuration
对于 @Configuration 最终会在 ConfigurationClassParser#processConfigurationClass
中先对 @Configuration 进行条件判断,此方法会调用 ConditionEvaluator#shouldSkip
进行判断,不满足则不再进行后续的解析

解析@ComponentScan
对于 @ComponentScan 扫描的配置类的条件判断发生在 ClassPathScanningCandidateComponentProvider#isCandidateComponent
中,此方法会调用 isConditionMatch()
方法进而来调用 ConditionEvaluator#shouldSkip
来进行判断


解析@Import
对于在 @Configuration 中使用 @Import 注解导入的配置类,要满足导入此配置类的类没有被判断为skip才会对导入的类进行注册,此方法会调用 TrackedConditionEvaluator#shouldSkip
进而调用 ConditionEvaluator#shouldSkip
来进行判断


解析@Bean
对于 @Configuration 中配置的 @Bean 方法返回的类的条件判断发生在 ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
中,此方法会调用 loadBeanDefinitionsForBeanMethod
方法进而调用 ConditionEvaluator#shouldSkip
来进行判断

聊聊@Profile
Spring 中提供了 @Profile 注解来实现候选组件对特定的一组环境名称满足条件时被注册使用,它就是基于 @Conditional
注解来实现的,此注解关联定义了 ProfileCondition ,在ProfileCondition 对Spring中的环境名进行匹配逻辑的处理


The @Profile annotation is actually implemented by using a much more flexible annotation called @Conditional.
@Profile与@Conditional的区别,@Profile侧重于环境,而@Conditional更通用
总结
Spring 通过提供 @Conditional
注解使 Spring 支持更加灵活的配置类注入控制,特别是支持多个条件配置,其核心处理逻辑在 ConditionEvaluator的shouldSkip方法。开发人员可以通过配置此类来打开关闭相关的功能(典型如Spring Boot的条件化装配),通常开发的基本功能配置可以通过增加 @Conditional
注解来判断只有在特定情况下才使用默认的配置,这对于模块化开发很有帮助。