
引言
上篇博文带大家从 Spring Boot 源码深入详解了 OnBeanCondition,那本篇也同样从源码入手,带大家深入了解 OnWebApplicationCondition 的过滤匹配实现。
主要内容
本篇我们重点详解 OnWebApplicationCondition 的实现,参见如下:
1. getOutcomes 方法
鉴于前面博文的了解,我们知道 OnWebApplicationCondition 也是 FilteringSpringBootCondition 的子类,所以这里同样也是从 getOutcomes 方法源码来分析【Spring Boot 2.7.9】:
1 |
|
上述逻辑很容易理解,遍历自动配置数组 autoConfigurationClasses ,循环如下:
首先,从
autoConfigurationClasses中获取自动配置数据autoConfigurationClass;然后,调用
AutoConfigurationMetadata接口的get(String className, String key)方法来获取与autoConfigurationClass关联的名为"ConditionalOnWebApplication"的条件属性值【即应用类型枚举值】;应用类型枚举可以查看
@ConditionalOnWebApplication注解获取,如下所示:
最后,调用
getOutcome方法,并传入上述获取的应用类型枚举值type:
- 如果
type是SERVLET, 则判断org.springframework.web.context.support.GenericWebApplicationContext是否存在;
如果不存在,则返回一个未满足过滤匹配条件的ConditionOutcome对象【其中包含 did not find servlet web application classes 的信息 】。 - 如果
type是REACTIVE,则判断org.springframework.web.reactive.HandlerResult是否存在;
如果不存在,则返回一个未满足过滤匹配条件的ConditionOutcome对象【其中包含 did not find reactive web application classes 的信息 】。 - 如果
org.springframework.web.context.support.GenericWebApplicationContext不存在且org.springframework.web.reactive.HandlerResult也不存在,则返回一个未满足过滤匹配条件的ConditionOutcome对象【其中包含 did not find reactive or servlet web application classes 的信息 】。 - 如果都存在,则直接返回
null。
- 如果
2. getMatchOutcome 方法
同 OnClassCondition 一样,OnWebApplicationCondition 同样实现了 FilteringSpringBootCondition 的父类 SpringBootCondition 中的抽象方法 getMatchOutcome 方法。
有关
SpringBootCondition的介绍,这里不赘述了,请查看笔者的 【Spring Boot 源码学习】OnClassCondition 详解。
那么,我们进入 getMatchOutcome 方法中查看如下源码【Spring Boot 2.7.9】:
1 |
|
我们来分析一下相关逻辑:
首先,通过调用
AnnotatedTypeMetadata接口的isAnnotated方法,判断元数据中是否存在@ConditionalOnWebApplication注解【当应用程序为 Web 应用程序时,该条件注解用来匹配】。如果返回true,表示元数据中存在指定注解;否则,返回false。然后,调用
isWebApplication方法来获取条件匹配结果outcome【有关内容查看 第 3 小节】;如果
required为true【即存在@ConditionalOnWebApplication注解】,并且 条件结果不匹配,则返回一个新的ConditionOutcome对象,标记为不匹配,并带有原始的消息。如果
required为false【即不存在@ConditionalOnWebApplication注解】,并且 条件结果匹配,则同样返回一个新的ConditionOutcome对象,标记为不匹配,并带有原始的消息。最后,上述两个条件判断都不满足,则将返回一个匹配的
ConditionOutcome对象,并带有原始的消息。
3. isWebApplication 方法
下面,我们进入 isWebApplication 方法中:
1 | private ConditionOutcome isWebApplication(ConditionContext context, AnnotatedTypeMetadata metadata, |
上述的逻辑也很简单:
首先,通过
deduceType方法获取可获取的应用类型;查看其源码可知,如果存在@ConditionalOnWebApplication注解,则获取其对应的type属性;否则默认返回Type.ANY【即任何Web应用程序都将匹配】。1
2
3
4
5
6
7private Type deduceType(AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnWebApplication.class.getName());
if (attributes != null) {
return (Type) attributes.get("type");
}
return Type.ANY;
}如果是
Type.SERVLET,则调用isServletWebApplication方法返回条件匹配结果。如果是
Type.REACTIVE,则调用isReactiveWebApplication方法返回条件匹配结果。如果不是上述两个应用类型,则默认调用
isAnyWebApplication方法返回条件匹配结果。
3.1 isServletWebApplication 方法
我们直接翻看 isServletWebApplication 方法的源码,如下:
1 | private ConditionOutcome isServletWebApplication(ConditionContext context) { |
我们来详细分析一下:
- 首先,检查类加载器中是否存在
org.springframework.web.context.support.GenericWebApplicationContext?- 如果没有,那么将返回不匹配的结果,并附带消息
"did not find servlet web application classes"。
- 如果没有,那么将返回不匹配的结果,并附带消息
- 如果条件上下文
context中BeanFactory不为空,则获取所有注册的scope名称,并检查其中是否包含"session"。如果包含,则返回匹配的结果,并附带消息"found session scope"。 - 如果条件上下文
context中Environment是ConfigurableWebEnvironment的实例,则将返回匹配的结果,并附带消息"found ConfigurableWebEnvironment"。 - 如果条件上下文
context中ResourceLoader是WebApplicationContext的实例,那么将返回匹配的结果,并附带消息"found WebApplicationContext"。 - 如果上述的条件都不满足,则最后将返回不匹配的结果,并附带消息
"not a servlet web application"。
3.2 isReactiveWebApplication 方法
同样,我们也先来查看下 isReactiveWebApplication 方法的源码,如下:
1 | private ConditionOutcome isReactiveWebApplication(ConditionContext context) { |
通过上述 isServletWebApplication 方法中的分析,我们可以很快总结下:
- 首先,检查类加载器中是否存在
org.springframework.web.reactive.HandlerResult?- 如果没有,那么将返回不匹配的结果,并附带消息
"did not find reactive web application classes"。
- 如果没有,那么将返回不匹配的结果,并附带消息
- 如果条件上下文
context中Environment是ConfigurableReactiveWebEnvironment的实例,则将返回匹配的结果,并附带消息"found ConfigurableReactiveWebEnvironment"。 - 如果条件上下文
context中ResourceLoader是ReactiveWebApplicationContext的实例,那么将返回匹配的结果,并附带消息"found ReactiveWebApplicationContext"。 - 如果上述的条件都不满足,则最后将返回不匹配的结果,并附带消息
"not a reactive web application"。
3.3 isAnyWebApplication 方法
还是一样,我们先来看看 isAnyWebApplication 方法的源码,如下:
1 | private ConditionOutcome isAnyWebApplication(ConditionContext context, boolean required) { |
这里就更简单了,总结如下:
- 首先,通过调用 isServletWebApplication 方法获取条件匹配结果;
- 如果
Servlet Web应用程序的条件结果匹配并且required为true,则返回一个包含匹配状态和相关消息的ConditionOutcome对象。
- 如果
- 接着,通过调用 isReactiveWebApplication 方法获取条件匹配结果;
- 如果
Reactive Web应用程序的条件结果匹配并且required为true,则同样返回一个包含匹配状态和相关消息的ConditionOutcome对象。 - 最后,如果上述两种情况都不满足 或者
required为false,则返回一个新的ConditionOutcome对象,它包含servletOutcome.isMatch() || reactiveOutcome.isMatch()的匹配状态 和servletOutcome与reactiveOutcome两者拼接的消息。
总结
本篇 Huazie 带大家从源码角度深入了解了自动配置过滤匹配子类 OnWebApplicationCondition ,至此 Spring Boot 中有关自动配置过滤匹配的三个实现已经介绍完毕,当然有关过滤匹配条件的内容还没结束,下一篇笔者将介绍 @Conditional 条件注解。
