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