Spring Conditional
- Author: HuiFer
- 源码阅读仓库: SourceHot-spring
Conditional
@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Conditional {/*** 多个匹配器接口*/Class<? extends Condition>[] value();}
Condition
@FunctionalInterfacepublic interface Condition {/*** 匹配,如果匹配返回true进行初始化,返回false跳过初始化*/boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);}
- ConditionContext 上下文
- AnnotatedTypeMetadata 注解信息
ConditionContext
public interface ConditionContext {/*** bean的定义*/BeanDefinitionRegistry getRegistry();/*** bean 工厂*/@NullableConfigurableListableBeanFactory getBeanFactory();/*** 环境*/Environment getEnvironment();/*** 资源加载器*/ResourceLoader getResourceLoader();/*** 类加载器*/@NullableClassLoader getClassLoader();}
唯一实现 :
org.springframework.context.annotation.ConditionEvaluator.ConditionContextImpl构造方法
public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {this.registry = registry;this.beanFactory = deduceBeanFactory(registry);this.environment = (environment != null ? environment : deduceEnvironment(registry));this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);}
- 在构造方法中加载了一些变量, 这些变量是根据一定规则转换后得到. 具体规则不展开.
AnnotatedTypeMetadata
- 元数据接口
public interface AnnotatedTypeMetadata {/*** 获取所有注解*/MergedAnnotations getAnnotations();/*** 是否有注解*/default boolean isAnnotated(String annotationName) {return getAnnotations().isPresent(annotationName);}/*** 获取注解的属性*/@Nullabledefault Map<String, Object> getAnnotationAttributes(String annotationName) {return getAnnotationAttributes(annotationName, false);}}
源码分析
- 对应测试类
org.springframework.context.annotation.ConfigurationClassWithConditionTests
@Testpublic void conditionalOnMissingBeanMatch() throws Exception {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);ctx.refresh();assertThat(ctx.containsBean("bean1")).isTrue();assertThat(ctx.containsBean("bean2")).isFalse();assertThat(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration")).isFalse();}@Configurationstatic class BeanOneConfiguration {@Beanpublic ExampleBean bean1() {return new ExampleBean();}}@Configuration@Conditional(NoBeanOneCondition.class)static class BeanTwoConfiguration {@Beanpublic ExampleBean bean2() {return new ExampleBean();}}static class NoBeanOneCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return !context.getBeanFactory().containsBeanDefinition("bean1");}}
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
shouldSkip
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<>();// 获取注解 Conditional 的属性值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();}// matches 进行验证if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {return true;}}return false;}
读取注解信息, 并且执行注解对应的类的方法
用例如下. 实例化
BeanTwoConfiguration对象的时候会去执行NoBeanOneCondition方法```java @Configuration @Conditional(NoBeanOneCondition.class) static class BeanTwoConfiguration {
@Bean public ExampleBean bean2() {
return new ExampleBean();
} }
static class NoBeanOneCondition implements Condition {
@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return !context.getBeanFactory().containsBeanDefinition("bean1");}}
在开发中可以自定义 matches 规则这也是在注册的时候第一个方法```javaprivate <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,@Nullable BeanDefinitionCustomizer[] customizers) {AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);// 和条件注解相关的函数if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}// 省略其他}
