spring?@Conditional的使用與擴展源碼分析
@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都需要實現(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ù)條件判斷是否注入對應(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;
}
}如果要測試LinuxCondition并不需要再linux系統(tǒng)下運行,只需要的啟動時設(shè)置環(huán)境參數(shù):-Dos.name=linux。
Conditional的擴展
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就不會對方法或類進行解析。
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的使用與擴展的文章就介紹到這了,更多相關(guān)spring @Conditional使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
新建springboot項目時,entityManagerFactory報錯的解決
這篇文章主要介紹了新建springboot項目時,entityManagerFactory報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
struts2簡介_動力節(jié)點Java學(xué)院整理
Struts2框架是MVC流程框架,適合分層開發(fā),這篇文章主要為大家詳細(xì)介紹了struts2簡介的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
MyBatisCodeHelperPro最新激活方法(有效方法)
這篇文章主要介紹了MyBatisCodeHelperPro最新激活方法親測有效,非常好用,小編今天以idea2021.2.1為例給大家詳細(xì)講解,需要的朋友可以參考下2022-08-08
Mybatis collection查詢集合屬性報錯的解決方案
這篇文章主要介紹了Mybatis collection查詢集合屬性報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

