spring?@Conditional的使用與擴(kuò)展源碼分析
@Conditional的使用
@Conditional可以根據(jù)條件來判斷是否注入某些Bean。
package com.morris.spring.config; import com.morris.spring.condition.LinuxCondition; import com.morris.spring.condition.WindowsCondition; import com.morris.spring.entity.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class ConditionalConfig { // 如果是windows系統(tǒng)就注入bill @Conditional(WindowsCondition.class) @Bean(name = "user") public User bill() { return new User("bill", 22); } // 如果是linux系統(tǒng)就注入linus @Conditional(LinuxCondition.class) public User linus() { return new User("linus", 20); }
WindowsCondition和LinuxCondition都需要實(shí)現(xiàn)Condition接口。
WindowsCondition
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class WindowsCondition implements Condition { /** * 根據(jù)條件判斷是否注入對(duì)應(yīng)的Bean * @param conditionContext 應(yīng)用上下文 * @param annotatedTypeMetadata 加了@Conditional注解的方法的元數(shù)據(jù)信息 * @return */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String osName = conditionContext.getEnvironment().getProperty("os.name"); if(osName.contains("Windows")) { return true; } return false; } }
LinuxCondition
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String osName = conditionContext.getEnvironment().getProperty("os.name"); if(osName.contains("linux")) { return true; } return false; } }
如果要測(cè)試LinuxCondition并不需要再linux系統(tǒng)下運(yùn)行,只需要的啟動(dòng)時(shí)設(shè)置環(huán)境參數(shù):-Dos.name=linux
。
Conditional的擴(kuò)展
ConditionalOnBean
ConditionalOnBeanc.java
package com.morris.spring.condition; import org.springframework.context.annotation.Conditional; import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) public @interface ConditionalOnBean { Class<?>[] value() default {}; }
OnBeanCondition.java
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class OnBeanCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnBean.class.getName()); Class<?>[] clazz = (Class<?>[]) annotationAttributes.get("value"); for (Class<?> aClass : clazz) { Map<String, ?> beans = context.getBeanFactory().getBeansOfType(aClass); if(beans.isEmpty()) { return false; } } return true; } }
ConditionalOnProperty
ConditionalOnProperty.java
package com.morris.spring.condition; import org.springframework.context.annotation.Conditional; import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { String[] value() default {}; }
OnPropertyCondition.java
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class OnPropertyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName()); String[] propertyArray = (String[]) annotationAttributes.get("value"); for (String property : propertyArray) { if(!context.getEnvironment().containsProperty(property)) { return false; } } return true; } }
源碼分析
如果Condition返回的是false,那么spirng就不會(huì)對(duì)方法或類進(jìn)行解析。
org.springframework.context.annotation.ConditionEvaluator#shouldSkip
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) { // 判斷類或方法上面是否有@Conditional注解 if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } if (phase == null) { if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) { return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION); } return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN); List<Condition> conditions = new ArrayList<>(); 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) { requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); // 調(diào)用condition.matches方法 if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) { return true; return false; }
到此這篇關(guān)于spring @Conditional的使用與擴(kuò)展的文章就介紹到這了,更多相關(guān)spring @Conditional使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring自動(dòng)配置之condition條件判斷上篇
- Spring?Boot?詳細(xì)分析Conditional自動(dòng)化配置注解
- Spring?Boot自動(dòng)配置的原理及@Conditional條件注解
- SpringBoot深入探究@Conditional條件裝配的使用
- SpringBoot中的Condition包下常用條件依賴注解案例介紹
- SpringBoot自動(dòng)配置特點(diǎn)與原理詳細(xì)分析
- SpringBoot自動(dòng)配置原理分析
- SpringBoot自動(dòng)配置深入探究實(shí)現(xiàn)原理
- Spring自動(dòng)配置之condition條件判斷下篇
相關(guān)文章
SpringBoot實(shí)現(xiàn)異步消息處理的代碼示例
在現(xiàn)代應(yīng)用程序中,異步消息處理是一項(xiàng)至關(guān)重要的任務(wù)。它可以提高應(yīng)用程序的性能、可伸縮性和可靠性,同時(shí)也可以提供更好的用戶體驗(yàn),本文將介紹如何使用Spring Boot實(shí)現(xiàn)異步消息處理,并提供相應(yīng)的代碼示例2023-06-06新建springboot項(xiàng)目時(shí),entityManagerFactory報(bào)錯(cuò)的解決
這篇文章主要介紹了新建springboot項(xiàng)目時(shí),entityManagerFactory報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01基于SpringBoot實(shí)現(xiàn)用戶身份驗(yàn)證工具
這篇文章主要介紹了基于SpringBoot實(shí)現(xiàn)的用戶身份驗(yàn)證工具,非常不錯(cuò),具有參考借鑒價(jià)值 ,需要的朋友可以參考下2018-04-04struts2簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Struts2框架是MVC流程框架,適合分層開發(fā),這篇文章主要為大家詳細(xì)介紹了struts2簡(jiǎn)介的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09MyBatisCodeHelperPro最新激活方法(有效方法)
這篇文章主要介紹了MyBatisCodeHelperPro最新激活方法親測(cè)有效,非常好用,小編今天以idea2021.2.1為例給大家詳細(xì)講解,需要的朋友可以參考下2022-08-08Mybatis collection查詢集合屬性報(bào)錯(cuò)的解決方案
這篇文章主要介紹了Mybatis collection查詢集合屬性報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09