SpringBoot-ConditionalOnBean
SpringBoot ConditionalOnBean
-
Author: HuiFer
-
源码阅读仓库: SourceHot-spring-boot
-
在 SpringBoot 中有下列当 XXX 存在或不存的时候执行初始化
- ConditionalOnBean ConditionalOnClass ConditionalOnCloudPlatform ConditionalOnExpression ConditionalOnJava ConditionalOnJndi ConditionalOnMissingBean ConditionalOnMissingClass ConditionalOnNotWebApplication ConditionalOnProperty ConditionalOnResource ConditionalOnSingleCandidate ConditionalOnWebApplication
ConditionalOnBean
|
|
SearchStrategy
|
|
OnBeanCondition
-
org.springframework.boot.autoconfigure.condition.OnBeanCondition
-
这个类是一个条件类,相关的还有
1 2 3 4
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ org.springframework.boot.autoconfigure.condition.OnClassCondition,\ org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
-
类图
在看这部分源码之前需要先了解 Conditional
和Condition
的源码
-
简单描述
通过实现
Condition
来确认是否初始化 bean -
从类图上我们可以看到
condition
的继承关系. 在这里需要去找到SpringBootCondition
-
org.springframework.boot.autoconfigure.condition.SpringBootCondition#matches(org.springframework.context.annotation.ConditionContext, org.springframework.core.type.AnnotatedTypeMetadata)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
@Override public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 类名或者方法名标记 String classOrMethodName = getClassOrMethodName(metadata); try { // 比较类,子类实现 ConditionOutcome outcome = getMatchOutcome(context, metadata); // 日志输出 logOutcome(classOrMethodName, outcome); // 报告记录 recordEvaluation(context, classOrMethodName, outcome); // 返回匹配结果 return outcome.isMatch(); } catch (NoClassDefFoundError ex) { throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to " + ex.getMessage() + " not found. Make sure your own configuration does not rely on " + "that class. This can also happen if you are " + "@ComponentScanning a springframework package (e.g. if you " + "put a @ComponentScan in the default package by mistake)", ex); } catch (RuntimeException ex) { throw new IllegalStateException("Error processing condition on " + getName(metadata), ex); } }
-
getOutcomes
子类实现org.springframework.boot.autoconfigure.condition.OnBeanCondition#getOutcomes
1 2
String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata
- 第一个参数: 需要自动配置的类
- 配置注解信息
ConditionOutcome 和 ConditionMessage
|
|
- 造一个对象用来进行 debug
|
|
getMatchOutcome
|
|
- 开始方法分析
getMatchingBeans
org.springframework.boot.autoconfigure.condition.OnBeanCondition#getMatchingBeans
|
|
- 在
MatchResult result = new MatchResult()
之前的代码作用是确认 ioc 容器
getNamesOfBeansIgnoredByType
|
|
getBeanNamesForType
|
|
getBeanNamesForType
|
|
collectBeanNamesForType
- 这里最终回到了 spring beanFactory 的方法 getBeanNamesForType
|
|
到这里需要忽略的 beanName 就全部找出来了
|
|
- 在忽略 bean 找到之后做一个类型移除的操作.
返回值
- 在返回之前做一堆判断条件. 一旦符合条件这个地方会做一个 noMatch 的一个对象(
ConditionOutcome
) ,通过返回 match 对象ConditionOutcome
|
|
|
|
- 到此结果封装完毕.回到方法
org.springframework.boot.autoconfigure.condition.SpringBootCondition#matches(org.springframework.context.annotation.ConditionContext, org.springframework.core.type.AnnotatedTypeMetadata)
继续进行- 再往后就继续执行 spring 的 bean 初始化咯
MessageSourceAutoConfiguration
-
启动阶段的一个类运行解读
-
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
1 2 3 4 5 6
@Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Conditional(ResourceBundleCondition.class) @EnableConfigurationProperties public class MessageSourceAutoConfiguration {}
-
根据类的注解信息我们可以找到有
ResourceBundleCondition
-
-
获取类名或者方法名的结果是
MessageSourceAutoConfiguration
全路径 -
继续往下是一个比较的方法(是否符合 match)
org.springframework.boot.autoconfigure.condition.SpringBootCondition#getMatchOutcome
这个方法是一个抽象方法子类实现 -
上图中红框内标注的类为
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.ResourceBundleCondition
同时继承
org.springframework.boot.autoconfigure.condition.SpringBootCondition
并且重写了方法
getMatchOutcome
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { // 从 容器中获取 String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages"); // 从缓存中获取条件信息 ConditionOutcome outcome = cache.get(basename); if (outcome == null) { // 生成条件信息对象 outcome = getMatchOutcomeForBasename(context, basename); // 放入缓存 cache.put(basename, outcome); } return outcome; }
这个方法主要将比较信息放入,
-
后续的行为依然是判断是否匹配,匹配就创建.
Spring Boot 启动阶段的自动注入
|
|
|
|
- 在这里有一个关注点 循环方法
getAutoConfigurationImportFilters()
|
|
在spring.factories
文件中找到AutoConfigurationImportFilter
后面的值
|
|
-
此时我们可以和前文的源码分析连接起来有一个完整的认识了
-
最后来看整体类图
- 原文作者:知识铺
- 原文链接:https://geek.zshipu.com/post/code/docs/SpringBoot/SpringBoot-ConditionalOnBean/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com