首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164…
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca…
一 . 前言
这一篇来看一下Conditional的使用和原理 , 先来看一下整体的体系结构
二 . 使用
- @ConditionalOnBean:当容器里有指定 Bean 的条件下。
- @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下。
- @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
- @ConditionalOnClass:当类路径下有指定类的条件下。
- @ConditionalOnMissingClass:当类路径下没有指定类的条件下。
- @ConditionalOnProperty:指定的属性是否有指定的值
- @ConditionalOnResource:类路径是否有指定的值
- @ConditionalOnExpression:基于 SpEL 表达式作为判断条件。
- @ConditionalOnJava:基于 Java 版本作为判断条件
- @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
- @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
- @ConditionalOnWebApplication:当前项目是 Web项 目的条件下
2.1 基础使用
2.2 自定义 Conditional
1 | java复制代码public class DefaultConditional implements Condition { |
2.3 基础使用
1 | java复制代码@Bean |
三 . 自定义原理分析
3.1 Conditional 入口
对于 Configuration.@Bean 的创建方式 , Conditinal 的起点是 refush# invokeBeanFactoryPostProcessors , 在其中会调用 ConfigurationClassPostProcessor 进行处理
1 | java复制代码private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { |
3.2 Conditional 判断的流程
ConditionEvaluator 是核心处理类 , 最终都会调用 shouldSkip 判断是否跳过
1 | java复制代码// C- ConditionEvaluator |
直到这里就开始匹配到对应的方法
四 .常规加载方式
解析
已知的Conditional 是基于 SpringBootCondition 实现的 , 其具体抽象类为 FilteringSpringBootCondition , 看一下主要的继承关系
去除不需要配置的类
第一步是快速去除不需要的类 , 主要流程如下 :
- 起点 : AbstractApplicationContext # refresh # invokeBeanFactoryPostProcessors
- 处理 : ConfigurationClassPostProcessor # postProcessBeanDefinitionRegistry 处理主要逻辑
- 拦截 : ConfigurationClassFilter # filter
- 匹配 : FilteringSpringBootCondition # match
注意 , 这里是进行 match 匹配 ,目的是获取基于正在导入的Configuration类的AnnotationMetadata的AutoConfigurationEntry
4.1 Filter 拦截
Filter 拦截是在 ConfigurationClassFilter ,其中会对所有的 Conditional 进行拦截处理
1 | java复制代码private static class ConfigurationClassFilter { |
4.2 FilteringSpringBootCondition 中 match 匹配
此处是重写了其父类的 match 方法
1 | java复制代码public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { |
ConditionEvaluationReport 的作用
该对象用来记录自动化配置过程中条件匹配的详细信息及日志信息
1 | java复制代码public final class ConditionEvaluationReport { |
4.3 getOutcomes 获取
此处以 OnBean 为例 , 此处存在一定的关联关系 :
1 | java复制代码protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, |
4.4 如何判断是否符合评估条件
注意 , 这里的 matches 和 FilteringSpringBootCondition 不是一个
- FilteringSpringBootCondition # match : 基于 AutoConfigurationImportFilter , 对给定的自动配置类候选应用筛选器
- SpringBootCondition # matches : 需要返回最终的判断结果
调用流程
- 在 loadBeanDefinitionsForBeanMethod 等类似流程种调用 shouldSkip , 从而跳转到该逻辑
1 | java复制代码@Override |
这里的核心就是调用 getMatchOutcome 判断是否符合或者不符合要求 , getMatchOutcome 需要子类重写
五 . getMatchOutcome 详情
5.1 OnClass
1 | java复制代码public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { |
补充 : ConditionMessage 的作用
5.2 OnBean
与 OnBean 类似 , 这里就展示一种
1 | java复制代码public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { |
总结
Conditional 本身并不难 , 这一篇主要是为了完善图谱以及后续的 starter 启动流程方案 做准备.
整个流程中有几个环节理解就行了 :
- Spring 中的 Conditional 都会继承 SpringBootCondition , 会实现其 getOutcomes 方法
- getOutcomes 是用于快速去掉无需加载的 Configuration , getMatchOutcome 是为了验证匹配关系
- 通常都会通过 ConditionEvaluator 的 shouldSkip 判断是否需要跳过@Bean 流程
本文转载自: 掘金