Spring @Conditional

目錄

 

@Conditional的使用

其他派生註解

源碼解析

@Conditional

加載流程

ConditionEvaluator

Spring boot派生註解

@ConditionalOnBean

@ConditionalOnMissingBean

@ConditionalOnClass

@ConditionalOnMissingClass

@ConditionalOnCloudPlatform

@ConditionalOnExpression

@ConditionalOnJava

@ConditionalOnJndi

@ConditionalOnNotWebApplication

@ConditionalOnProperty

@ConditionalOnResource

@ConditionalOnSingleCandidate

@ConditionalOnWebApplication

Condition實現類

ConfigurationCondition

SpringBootCondition

FilteringSpringBootCondition 

OnClassCondition 


@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);
	}
    

 

發佈了174 篇原創文章 · 獲贊 21 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章