SpringBoot内置http编码功能为例分析自动配置过程( 三 )


SpringBoot内置http编码功能为例分析自动配置过程文章插图
上一节我们已经学习了 Condition 接口的源码 , 那么抽象类 SpringBootCondition 是如何实现该方法的呢?相关源代码如下 。
public abstract class SpringBootCondition implements Condition {@Overridepublic final boolean matches (ConditionContext context ,AnnotatedTypeMetadata metadata) {ConditionOutcome outcome = getMatchOutcome(context, metadata);return outcome . isMatch();}public abstract ConditionOutcome getMatchOutcome ( ConditionContext context,AnnotatedTypeMetadata metadata) ;}在抽象类 SpringBootCondition 中实现了 matches 方法 , 而该方法中最核心的部分是通过调用新定义的抽象方法 getMatchOutcome 并交由子类来实现 , 在 matches 方法中根据子类返回的结果判断是否匹配 。 下面我们来看 OnWebApplicationCondition 的源代码是如何实现相关功能的 。
@Order(Ordered . HIGHEST_ PRECEDENCE + 20)class OnWebApplicationCondition extends FilteringSpringBootCondition {@Overridepublic ConditionOutcome getMatchOutcome(ConditionContext context ,AnnotatedTypeMetadata metadata) {boolean required = metadata . isAnnotated (Condit ionalOnWebApplication.cla55.getName());ConditionOutcome outcome = isWebApplication(context, metadata, required);if (required if (!required return ConditionOutcome . match(outcome . getConditionMessage());}可 以 看 出,是 否 匹 配 是 由 两 个 条 件 决 定 的 : 被 注 解 的 类 或 方 法 是 否 包 含ConditionalOn-WebApplication 注解 , 是否为 Web 应用 。
.如 果包含 ConditionalOn WebApplication 注解 , 并且不是 Web 应用 , 那么返回不匹配 。
.如果不包含 ConditionalOnWebApplication 注解 , 并且是 Web 应用 , 那么返回不匹配 。
.其他情况 , 返回匹配 。
下面我们以 SERVLET Web 应用为例 , 看相关源代码是如何判断是否为 Web 应用的 。 REACTIVE Web 应用和其他类型的 Web 应用可参照学习 。
@Order (Ordered .HIGHEST PRECEDENCE + 20)class OnWebApplicationCondition extends FilteringSpringBootConditionprivate static final String SERVLET_ WEB_ APPLICATION_ CLASS = "org. springframework .web. . context . support . Gener icWebApplicationContext";//推断 web 应用是否匹配private ConditionOutcome isWebApplication(ConditionContext context,AnnotatedTypeMetadata metadata, boolean required) {switch (deduceType(metadata)) {case SERVLET://是否为 SERVLETreturn isServletWebApplication(context);case REACTIVE:'是否为 REACTIVEreturn isReactiveWebApplication(context);default://其他return isAnyWebApplication(context, required);}private ConditionOutcome isServletWebApplication(ConditionContext context) {ConditionMessage . Builder message = ConditionMessage . forCondition("");//判断常量定义类是否存在if (!ClassNameFilter . isPresent(SERVLET_ WEB_ APPLICATION_ CLASS,context . getClassLoader())) {return ConditionOutcome . noMatch(message. didNotFind("servlet web application classes").atAll());}//判断 BeanFactory 是否存在if (context . getBeanFactory() != null) {String[] scopes = context. getBeanFactory() . getRegisteredScopeNames();if (ObjectUtils . containsElement(scopes, "session")) {return ConditionOutcome . match(message . foundExactly("'session' scope"));}//判断 Environment 的类型是否为 Configurabl evebEnvironment 类型if (context . getEnvironment() instanceof ConfigurableWebEnvironment) {return ConditionOutcome.match(message . foundExactly("ConfigurableWebEnvironment"));//判断 ResourceLoader 的类型是否为 webAppl icat ionContext 类型if (context . getResourceLoader() instanceof WebApplicat ionContext) {return ConditionOutcome . match(message . foundExactly( "WebApplicationConreturn ConditionOut come . noMatch(message . because("not a servlet web-application"));// MAnnotatedTypeMetadata 中获取 type 值private Type deduceType(AnnotatedTypeMetadata metadata) {Map attributes = metadata. getAnnotat ionAttributes(Condit iona lOnWebApplicat ion. class . getName());if (attributes != nul1) {return (Type) attributes.get("type");return Type . ANY;}}


推荐阅读