admin管理员组文章数量:1599531
【源码】Spring —— Condition 条件匹配解读
- 前言
- 版本
- ConditionEvaluator
- ConditionContextImpl
- shouldSkip
- ConfigurationPhase
- 总结
前言
在注册 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) {
// 必须被 Conditional 注解标注
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
// 分析给定 metadata 的 ConfigurationPhase
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<>();
// 此处 getConditionClasses 方法返回的是所有 Conditional 注解的 value 属性
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
// 排序
AnnotationAwareOrderComparator.sort(conditions);
// 调用所有 Condition 的 match 方法进行匹配
// 有一个不匹配则返回 true,即 shouldSkip(应该跳过注册目标 BeanDefinition)
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// 过滤对应 ConfigurationPhase 的 Condition
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
------------------- getConditionClasses -------------------
@SuppressWarnings("unchecked")
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
/**
* getAllAnnotationAttributes 方法会追溯所有的注解
* 换句话说,即便定义在其注解下(例如 ConditionalOnXXX)
* 也是可以追溯到并合并其属性的
*/
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 ----------------------
// 返回指定的 Condition 实例
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
之间的依赖关系,我们平时的开发工作中也避免不了频繁的使用
版权声明:本文标题:【源码】Spring —— Condition 条件匹配解读 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1728323100a1154082.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论