【源码】Spring —— Condition 条件匹配解读
前言版本ConditionEvaluatorConditionContextImplshouldSkipConfigurationPhase
总结
前言
在注册 BeanDefinition 之前,会根据其 @Conditional 注解的条件进行过滤,@Conditional 是个 Spring内部 和 用户自定义 bean 之间依赖关系很实用的一个注解,该章节解读 Condition条件匹配 的相关类
版本
Spring 5.2.x
ConditionEvaluator
仅限 Spring内部 使用的类,判断目标 BeanDefinition 是否应该跳过注册
目标 BeanDefinition 的 上下文环境 由其内部类 ConditionContextImpl 维护
ConditionContextImpl
private static class ConditionContextImpl implements ConditionContext {
@Nullable
private final BeanDefinitionRegistry registry
;
@Nullable
private final ConfigurableListableBeanFactory beanFactory
;
private final Environment environment
;
private final ResourceLoader resourceLoader
;
@Nullable
private final ClassLoader classLoader
;
}
维护了 BeanDefinitionRegistry、ConfigurableListableBeanFactory 等相关 上下文属性
shouldSkip
public boolean shouldSkip(AnnotatedTypeMetadata metadata
) {
return shouldSkip(metadata
, null
);
}
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata
, @Nullable ConfigurationPhase phase
) {
if (metadata
== null
|| !metadata
.isAnnotated(Conditional
.class.getName())) {
return false;
}
if (phase
== null
) {
if (metadata
instanceof AnnotationMetadata &&
ConfigurationClassUtils
.isConfigurationCandidate((AnnotationMetadata
) metadata
)) {
return shouldSkip(metadata
, ConfigurationPhase
.PARSE_CONFIGURATION
);
}
return shouldSkip(metadata
, ConfigurationPhase
.REGISTER_BEAN
);
}
List
<Condition> conditions
= new ArrayList<>();
for (String
[] conditionClasses
: getConditionClasses(metadata
)) {
for (String conditionClass
: conditionClasses
) {
Condition condition
= getCondition(conditionClass
, this.context
.getClassLoader());
conditions
.add(condition
);
}
}
AnnotationAwareOrderComparator
.sort(conditions
);
for (Condition condition
: conditions
) {
ConfigurationPhase requiredPhase
= null
;
if (condition
instanceof ConfigurationCondition) {
requiredPhase
= ((ConfigurationCondition
) condition
).getConfigurationPhase();
}
if ((requiredPhase
== null
|| requiredPhase
== phase
) && !condition
.matches(this.context
, metadata
)) {
return true;
}
}
return false;
}
------------------- getConditionClasses
-------------------
@SuppressWarnings("unchecked")
private List
<String
[]> getConditionClasses(AnnotatedTypeMetadata metadata
) {
MultiValueMap
<String, Object> attributes
= metadata
.getAllAnnotationAttributes(Conditional
.class.getName(), true);
Object values
= (attributes
!= null
? attributes
.get("value") : null
);
return (List
<String
[]>) (values
!= null
? values
: Collections
.emptyList());
}
---------------------- getCondition
----------------------
private Condition
getCondition(String conditionClassName
, @Nullable ClassLoader classloader
) {
Class
<?> conditionClass
= ClassUtils
.resolveClassName(conditionClassName
, classloader
);
return (Condition
) BeanUtils
.instantiateClass(conditionClass
);
}
具体的细节给出了详细的注释,这里总结一下大体流程
整个方法可以理解为一个简单的 递归:
方法会在第一次 shouldSkip 判断目标 BeanDefinition 的 ConfigurationPhase 类型
再次进入 shouldSkip 方法,获取对应 @Conditional 注解上 value 属性的值,解析并获取对应的 Condition 实例,再以 ConfigurationPhase 过滤后,执行 match 方法检测条件是否匹配
但凡有一个 Condition 不匹配,则返回 true,标识该 BeanDefinition 跳过注册
ConfigurationPhase
public interface ConfigurationCondition extends Condition {
ConfigurationPhase
getConfigurationPhase();
enum ConfigurationPhase
{
PARSE_CONFIGURATION
,
REGISTER_BEAN
}
}
---------------------Condition
--------------------------
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context
, AnnotatedTypeMetadata metadata
);
}
ConfigurationPhase 是 Condition 的子接口 ConfigurationCondition 的一个内部 枚举类,定义了两种 Condition
PARSE_CONFIGURATION:表明该类 Condition 在解析 @Configuration 时检测匹配REGISTER_BEAN:表明该类 Condition 在注册 普通Bean 时检测匹配
总结
匹配 @Conditional 注解条件的 BeanDefinition 才有机会被注册,Spring内部 大量的使用了该注解来维护 bean 之间的依赖关系,我们平时的开发工作中也避免不了频繁的使用