javascript
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();@NullableConfigurableListableBeanFactory getBeanFactory();Environment getEnvironment();ResourceLoader getResourceLoader();@NullableClassLoader 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());@Overridepublic 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 SpringBootConditionimplements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {private BeanFactory beanFactory;private ClassLoader beanClassLoader;@Overridepublic 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
@Overridepublic 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);}?
總結
以上是生活随笔為你收集整理的Spring @Conditional的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Environment
- 下一篇: Spring boot mongodb