目录
@ConditionalOnNotWebApplication
@Conditional的使用
- 作用:根据条件,决定类是否加载到Spring Ioc容器中
- 应用场景:在一些需要条件满足才实例化的类上使用此注解
其他派生注解
- @ConditionalOnMissingBean
只有对应的bean在系统中都没有被创建,它注解的初始化代码块才会执行,用户自己手动创建的bean优先
- @ConditionalOnBean
仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。
- @ConditionalOnClass
某个class位于类路径上,才会实例化一个Bean
- @ConditionalOnExpression
当表达式为true的时候,才会实例化一个Bean。
- @ConditionalOnMissingClass
某个class类路径上不存在的时候,才会实例化一个Bean
- @ConditionalOnNotWebApplication
不是web应用
- @ConditionalOnProperty
当属性满足条件时配置
//当 filter.loginFilter = true时生效
@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true")
源码解析
@Conditional
public @interface Conditional {
Class<? extends Condition>[] value();
}
value属性值必须是一组继承于Condition的类。在Condition类中只有一个方法matches方法。这类的作用是,在bean的定义即将被注册之前,会检查条件是否匹配,然后根据匹配的结果决定是否注册bean。
@FunctionalInterface
public interface Condition {
/**
* 判断是否满足条件
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
ConditionContext封装了IOC容器的信息。
public interface ConditionContext {
BeanDefinitionRegistry getRegistry();
@Nullable
ConfigurableListableBeanFactory getBeanFactory();
Environment getEnvironment();
ResourceLoader getResourceLoader();
@Nullable
ClassLoader getClassLoader();
}
加载流程
通过查看Condition的matches在哪里被调用。发现整个spring中只有在ConditionEvaluator中调用了这个方法。这个类的作用是评估一个贴了Conditional注解的类是否需要跳过。通过类上面的注解来判断。此方法的调用是由ConfigurationClassPostProcessor引起的,用于处理@Configuration的解析(参考:SpringBoot启动流程)。
//ConfigurationClassPostProcessor:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
}
ConditionEvaluator
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
没有注解 @Conditional,则返回false,caller则继续处理。
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
//bean的注解信息封装对象是AnnotationMetadata类型并且,类上有@Component,@ComponentScan,@Import,@ImportResource,则表示为配置类型(此处是一直往最原始的注解追溯)
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
//表示是配置是bean类型
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
//从bean的注解信息封装对象中获取所有的Conditional类型或者Conditional的派生注解
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
//排序
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
//获取需要对bean进行的操作,是解析还是注册
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
//(如果requiredPhase==null或者指定的操作类型是目前阶段的操作类型)并且不符合设置的条件则跳过
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
Spring boot派生注解
@ConditionalOnBean
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
Class<?>[] value() default {};
String[] type() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {};
}
@ConditionalOnMissingBean
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
String[] type() default {};
Class<?>[] ignored() default {};
String[] ignoredType() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {};
}
@ConditionalOnClass
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
@ConditionalOnMissingClass
@Conditional(OnClassCondition.class)
public @interface ConditionalOnMissingClass {
String[] value() default {};
}
@ConditionalOnCloudPlatform
@Conditional(OnCloudPlatformCondition.class)
public @interface ConditionalOnCloudPlatform {
CloudPlatform value();
}
@ConditionalOnExpression
@Conditional(OnExpressionCondition.class)
public @interface ConditionalOnExpression {
String value() default "true";
}
@ConditionalOnJava
@Conditional(OnJavaCondition.class)
public @interface ConditionalOnJava {
Range range() default Range.EQUAL_OR_NEWER;
JavaVersion value();
enum Range {
EQUAL_OR_NEWER,
OLDER_THAN
}
}
@ConditionalOnJndi
@Conditional(OnJndiCondition.class)
public @interface ConditionalOnJndi {
String[] value() default {};
}
@ConditionalOnNotWebApplication
@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnNotWebApplication {
}
@ConditionalOnProperty
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
String[] value() default {};
String prefix() default "";
String[] name() default {};
String havingValue() default "";
boolean matchIfMissing() default false;
}
@ConditionalOnResource
@Conditional(OnResourceCondition.class)
public @interface ConditionalOnResource {
String[] resources() default {};
}
@ConditionalOnSingleCandidate
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnSingleCandidate {
Class<?> value() default Object.class;
String type() default "";
SearchStrategy search() default SearchStrategy.ALL;
}
@ConditionalOnWebApplication
@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnWebApplication {
Type type() default Type.ANY;
enum Type {
ANY,
SERVLET,
REACTIVE
}
}
Condition实现类
ConfigurationCondition
public interface ConfigurationCondition extends Condition {
ConfigurationPhase getConfigurationPhase();
enum ConfigurationPhase {
PARSE_CONFIGURATION,
REGISTER_BEAN
}
}
SpringBootCondition
public abstract class SpringBootCondition implements Condition {
private final Log logger = LogFactory.getLog(getClass());
@Override
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//从封装condition注解信息的类中获取指定的Condition类的实现类
String classOrMethodName = getClassOrMethodName(metadata);
try {
//确定匹配结果以及日志输出对象
ConditionOutcome outcome = getMatchOutcome(context, metadata);
logOutcome(classOrMethodName, outcome);
//将匹配结果进行存储
recordEvaluation(context, classOrMethodName, outcome);
//返回匹配的结果
return outcome.isMatch();
}
catch (NoClassDefFoundError ex) {
}
catch (RuntimeException ex) {
throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
}
}
/**
*由子类实现
*/
public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata);
}
FilteringSpringBootCondition
abstract class FilteringSpringBootCondition extends SpringBootCondition
implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
private BeanFactory beanFactory;
private ClassLoader beanClassLoader;
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
boolean[] match = new boolean[outcomes.length];
for (int i = 0; i < outcomes.length; i++) {
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
if (!match[i] && outcomes[i] != null) {
logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
}
}
}
return match;
}
protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata);
}
OnClassCondition
OnClassCondition用于@ConditionalOnClass和@ConditionalOnMissingClass
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ClassLoader classLoader = context.getClassLoader();
ConditionMessage matchMessage = ConditionMessage.empty();
返回ConditionalOnClass的value,name属性的值列表,
List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
if (onClasses != null) {
返回未被加载的class列表。
List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
if (!missing.isEmpty()) {
如果missling为空,表示没有匹配的,返回未匹配结果。
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class", "required classes").items(Style.QUOTE, missing));
}
matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
.found("required class", "required classes")
.items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
}
List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
if (onMissingClasses != null) {
返回所有加载的class列表
List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
if (!present.isEmpty()) {
如果不为空,则表示有加载的,返回未匹配。
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)
.found("unwanted class", "unwanted classes").items(Style.QUOTE, present));
}
matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
.didNotFind("unwanted class", "unwanted classes")
.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
}
返回匹配
return ConditionOutcome.match(matchMessage);
}