通过前面的文章,我们学习了SpringBoot的自动配置实现过程,其中涉及到条件注解。本文对条件注解进行介绍。
自动配置实现原理可见下列文章:
SpringBoot源码学习系列——自动配置原理(一)
SpringBoot源码学习系列——自动配置原理(二)
@Conditional条件注解
@Conditional注解介绍
@Conditional及其衍生注解用于某个类后,可以根据注解属性值指定的条件来决定是否进行Bean的实例化操作。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All Conditions that must match
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
可以看出,@Conditional
的属性为Condition
类型的数组,当数组中所有Condition#match
方法返回true时,被注解的类才可以进行实例化。
@FunctionalInterface
public interface Condition {
// 参数context:该接口方法用于获取Spring应用上下文信息
// 参数metadata:该接口方法用于检查带有@Bean注解的类上是否存在其他类型注解,获取各注解的属性信息
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Condition接口介绍
@Conditional
条件注解包含很多衍生注解,此处以@ConditionalOnWebApplication
为例介绍,可以看到,@ConditionalOnWebApplication
使用了@Conditional
注解,并且指定条件OnWebApplicationCondition.class
OnWebApplicationCondition.class
类继承如下,继承自FilteringSpringBootCondition
,FilteringSpringBootCondition
又继承自SpringBootCondition
且实现了AutoConfigurationImportFilter
、BeanFactoryAware
、BeanClassLoaderAware
接口,SpringBootCondition
继承自Condition
接口,则肯定实现了matches
方法
下面看下SpringBootCondition
抽象类:
核心功能通过getMatchOutcome
方法实现,该方法是SpringBootCondition
抽象类的一个抽象方法,交由子类实现。
下面以OnWebApplicationCondition.class
为例,介绍getMatchOutcome
方法:
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 是否包含ConditionalOnWebApplication注解
boolean required = metadata.isAnnotated(ConditionalOnWebApplication.class.getName());
// 是否是web应用
ConditionOutcome outcome = isWebApplication(context, metadata, required);
// 使用了ConditionalOnWebApplication注解且不是web应用,则不匹配
if (required && !outcome.isMatch()) {
return ConditionOutcome.noMatch(outcome.getConditionMessage());
}
// 未使用ConditionalOnWebApplication注解且是web应用,则不匹配
if (!required && outcome.isMatch()) {
return ConditionOutcome.noMatch(outcome.getConditionMessage());
}
// 其它情况则匹配
return ConditionOutcome.match(outcome.getConditionMessage());
}