Spring @Conditional注解從源碼層講解
本文通過閱讀@Conditional注解、Condition接口、ConditionEvaluator類以及@ConditionalOnProperty(Spring Boot提供)注解源碼,深入分析Spring Conditional的實(shí)現(xiàn)原理。
源碼版本
由于不同版本的spring代碼實(shí)現(xiàn)細(xì)節(jié)可能存在差異,此處記錄一下本文使用的源碼版本:
- spring 5.2.12.RELEASE
- spring-boot 2.3.8.RELEASE
@Conditional注解
標(biāo)注在類或方法上,當(dāng)所有指定Condition都匹配時(shí),才允許向spring容器注冊(cè)組件。
如果一個(gè)@Configuration類標(biāo)注了@Conditional注解,則與該類關(guān)聯(lián)的所有@Bean方法、@Import注解和@ComponentScan注解都將受指定Condition約束。
注解定義:
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional {
/**
* 當(dāng)所有指定Condition都匹配時(shí),才允許向spring容器注冊(cè)組件。
*
* 這個(gè)泛型的意思是接受所有Condition接口的實(shí)現(xiàn)類。
*/
Class<? extends Condition>[] value();
}
Condition接口
Condition接口
匹配條件。
在注冊(cè)BeanDefinition之前立即檢查條件,并且可以根據(jù)當(dāng)時(shí)可以確定的任何條件取消組件注冊(cè)。
Condition必須遵循與BeanFactoryPostProcessor相同的限制,并注意不要與bean實(shí)例交互。如果需要對(duì)與@Configuration bean交互的Condition進(jìn)行更細(xì)粒度的控制,請(qǐng)考慮實(shí)現(xiàn)ConfigurationCondition接口。
接口定義:
public interface Condition {
/**
* 確定條件是否匹配。
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
ConditionContext接口
用于獲取BeanDefinitionRegistry、BeanFactory、Environment等。
只有一個(gè)ConditionEvaluator.ConditionContextImpl實(shí)現(xiàn)類(一個(gè)內(nèi)部類):
class ConditionEvaluator {
private final ConditionContextImpl context;
public ConditionEvaluator(BeanDefinitionRegistry registry,
Environment environment, ResourceLoader resourceLoader) {
this.context = new ConditionContextImpl(registry, environment, resourceLoader);
}
ConditionEvaluator類
用于處理Conditional相關(guān)注解。
核心的邏輯都在這個(gè)類里面:
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
// 1. 判斷目標(biāo)組件是否被Conditional標(biāo)注
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);
}
// 2. 獲取到所有的Condition并實(shí)例化
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
// 3. Condition排序
AnnotationAwareOrderComparator.sort(conditions);
// 4. Condition匹配驗(yàn)證
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) &&
!condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
核心功能4步:
- 判斷目標(biāo)組件是否被Conditional標(biāo)注
- 獲取到所有的Condition并實(shí)例化
- Condition排序
- Condition匹配驗(yàn)證
下文將展開說明這4個(gè)步驟。
判斷目標(biāo)組件是否被Conditional標(biāo)注
AnnotatedTypeMetadata中封裝了目標(biāo)組件的注解元信息,可以通過他獲取到目標(biāo)組件的注解相關(guān)信息,比如是否被某個(gè)注解標(biāo)注、某個(gè)注解的屬性等。
metadata.isAnnotated(Conditional.class.getName())
AnnotatedTypeMetadata中定義了該方法的實(shí)現(xiàn)方式:
default boolean isAnnotated(String annotationName) {
// 通過MergedAnnotations來獲取注解標(biāo)注狀態(tài)
return getAnnotations().isPresent(annotationName);
}
我們?cè)谥暗摹禨pring-@Bean注解源碼分析》中介紹過,此處使用的是StandardAnnotationMetadata實(shí)現(xiàn)類,而該類中的MergedAnnotations是使用以下方式創(chuàng)建和獲取的:
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
super(introspectedClass);
// 這里使用的是TypeMappedAnnotations實(shí)現(xiàn)類
this.mergedAnnotations = MergedAnnotations.from(introspectedClass,
SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none());
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
@Override
public MergedAnnotations getAnnotations() {
return this.mergedAnnotations;
}
所以isAnnotated的核心判斷邏輯在TypeMappedAnnotations的isPresent方法中:
public boolean isPresent(String annotationType) {
if (this.annotationFilter.matches(annotationType)) {
return false;
}
return Boolean.TRUE.equals(scan(annotationType,
IsPresent.get(this.repeatableContainers, this.annotationFilter, false)));
}
scan方法的詳細(xì)邏輯還是使用java反射的Class.getDeclaredAnnotations()方法來實(shí)現(xiàn)的,此處不展開說明,后續(xù)會(huì)有專門的章節(jié)介紹。
獲取到所有的Condition并實(shí)例化
// 2. 獲取到所有的Condition并實(shí)例化
List<Condition> conditions = new ArrayList<>();
// 獲取Condition集
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 創(chuàng)建Condition實(shí)例
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
// 這個(gè)方法從AnnotatedTypeMetadata中獲取所有Conditional注解指定的Condition類名集
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> attributes =
metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
Object values = (attributes != null ? attributes.get("value") : null);
return (List<String[]>) (values != null ? values : Collections.emptyList());
}
AnnotatedTypeMetadata接口getAllAnnotationAttributes方法,這是一個(gè)default方法,用于獲取指定注解的Attribute集:
default MultiValueMap<String, Object> getAllAnnotationAttributes(
String annotationName, boolean classValuesAsString) {
Adapt[] adaptations = Adapt.values(classValuesAsString, true);
return getAnnotations().stream(annotationName) // 獲取到所有的注解信息
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)) // 過濾
.map(MergedAnnotation::withNonMergedAttributes)
.collect(MergedAnnotationCollectors.toMultiValueMap(map ->
map.isEmpty() ? null : map, adaptations));
}
getAnnotations()返回的是TypeMappedAnnotations類型對(duì)象,他的stream方法:
public <A extends Annotation> Stream<MergedAnnotation<A>> stream(String annotationType) {
if (this.annotationFilter == AnnotationFilter.ALL) {
return Stream.empty();
}
// 這里使用java api創(chuàng)建Stream
return StreamSupport.stream(spliterator(annotationType), false);
}
private <A extends Annotation> Spliterator<MergedAnnotation<A>> spliterator(Object annotationType) {
return new AggregatesSpliterator<>(annotationType, getAggregates());
}
private List<Aggregate> getAggregates() {
List<Aggregate> aggregates = this.aggregates;
if (aggregates == null) {
// 這里掃描所有注解
aggregates = scan(this, new AggregatesCollector());
if (aggregates == null || aggregates.isEmpty()) {
aggregates = Collections.emptyList();
}
this.aggregates = aggregates;
}
return aggregates;
}
// 這里掃描所有注解
private <C, R> R scan(C criteria, AnnotationsProcessor<C, R> processor) {
if (this.annotations != null) {
R result = processor.doWithAnnotations(criteria, 0, this.source, this.annotations);
return processor.finish(result);
}
if (this.element != null && this.searchStrategy != null) {
return AnnotationsScanner.scan(criteria, this.element, this.searchStrategy, processor);
}
return null;
}
scan方法里面會(huì)通過遞歸方式使用java反射api從組件類getAnnotations以便獲取到所有的注解信息,代碼較多,此處不展開記錄。
Condition排序
- 判斷Condition類實(shí)現(xiàn)了PriorityOrdered接口,并使用PriorityOrdered進(jìn)行排序
- 判斷Condition類實(shí)現(xiàn)了Ordered接口,并使用Ordered進(jìn)行排序
- 從Condition類獲取Order注解,并使用Order注解的值進(jìn)行排序
AnnotationAwareOrderComparator.sort(conditions);
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE); // 這里的Comparator使用的是AnnotationAwareOrderComparator實(shí)現(xiàn)類
}
}
AnnotationAwareOrderComparator實(shí)現(xiàn)類:
public class AnnotationAwareOrderComparator extends OrderComparator {
@Override
protected Integer findOrder(Object obj) {
// 先使用父類方法獲取排序,其實(shí)就是判斷Ordered實(shí)現(xiàn)并獲取排序,在本例中顯然獲取不到
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// 從類標(biāo)注的注解中獲取排序
return findOrderFromAnnotation(obj);
}
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = (obj instanceof AnnotatedElement ?
(AnnotatedElement) obj : obj.getClass());
MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
// 從類標(biāo)注的注解中獲取排序,比如Order注解,此處不展開記錄了
Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
if (order == null && obj instanceof DecoratingProxy) {
return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
}
return order;
}
@Override
public Integer getPriority(Object obj) {
if (obj instanceof Class) {
return OrderUtils.getPriority((Class<?>) obj);
}
Integer priority = OrderUtils.getPriority(obj.getClass());
if (priority == null && obj instanceof DecoratingProxy) {
return getPriority(((DecoratingProxy) obj).getDecoratedClass());
}
return priority;
}
}
public class OrderComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) {
// 優(yōu)先級(jí)排序判斷
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
} else if (p2 && !p1) {
return 1;
}
// 分別獲取到order并比較
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
private int getOrder(Object obj, OrderSourceProvider sourceProvider) {
Integer order = null;
if (obj != null && sourceProvider != null) {
Object orderSource = sourceProvider.getOrderSource(obj);
if (orderSource != null) {
if (orderSource.getClass().isArray()) {
for (Object source : ObjectUtils.toObjectArray(orderSource)) {
order = findOrder(source);
if (order != null) {
break;
}
}
} else {
order = findOrder(orderSource);
}
}
}
// 直接執(zhí)行這里
return (order != null ? order : getOrder(obj));
}
protected int getOrder(Object obj) {
if (obj != null) {
// 繼續(xù)調(diào)用findOrder獲取排序
// 在此處場景下調(diào)用AnnotationAwareOrderComparator的findOrder方法
Integer order = findOrder(obj);
if (order != null) {
return order;
}
}
return Ordered.LOWEST_PRECEDENCE;
}
protected Integer findOrder(Object obj) {
return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
}
public Integer getPriority(Object obj) {
return null;
}
}
Condition匹配驗(yàn)證
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) &&
!condition.matches(this.context, metadata)) {
return true;
}
}
@ConditionalOnProperty注解和OnPropertyCondition類
@ConditionalOnProperty注解
@Conditional that checks if the specified properties have a specific value. By default the properties must be present in the Environment and not equal to false. The havingValue() and matchIfMissing() attributes allow further customizations.
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
String[] value() default {};
String prefix() default "";
String[] name() default {};
String havingValue() default "";
boolean matchIfMissing() default false;
}
OnPropertyCondition從env中檢測(cè)指定env參數(shù)是否配置了指定的值,只有滿足時(shí)才允許裝配目標(biāo)組件。
如何判斷被@Conditional注解標(biāo)注
前面已經(jīng)介紹,spring是使用(AnnotatedTypeMetadata)metadata.isAnnotated(Conditional.class.getName())來判斷組件被@Conditional注解標(biāo)注的。但是@Conditional標(biāo)注在@ConditionalOnProperty注解上,使用普通的(Class)clazz.isAnnotationPresent(Conditional.class)方式無法判斷,那么metadata.isAnnotated方法是如何判斷的呢?
從上面@ConditionalOnProperty注解定義可以知道,目標(biāo)組件類標(biāo)注了@ConditionalOnProperty注解,@ConditionalOnProperty注解又標(biāo)注了@Conditional注解,這顯然是一個(gè)遞歸,只有從目標(biāo)組件類開始遞歸解析,就可以解析出目標(biāo)組件類上的所有注解,以下是一個(gè)我自己編寫的簡單示例:
@EnableAspectJAutoProxy
@Configuration
@ComponentScan("org.net5ijy.mybatis.test.config.aop")
@ConditionalOnAop
public class ServiceAopConfig {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(AopCondition.class)
public @interface ConditionalOnAop {}
@Test
public void testAllResolveAnnotations() {
// 不解析以下三個(gè)注解
Set<Class<?>> exclude = new HashSet<Class<?>>() {{
add(Target.class);
add(Retention.class);
add(Documented.class);
}};
// 存放所有注解
List<Annotation> annotationList = new ArrayList<>();
// 首先獲取一次組件類直接標(biāo)注的注解
Annotation[] annotations = ServiceAopConfig.class.getDeclaredAnnotations();
// 遞歸解析
while (annotations.length > 0) {
annotationList.addAll(Arrays.asList(annotations));
// 遞歸解析
List<Annotation> tmp = new ArrayList<>();
for (Annotation annotation : annotations) {
Annotation[] list = annotation.annotationType().getDeclaredAnnotations();
for (Annotation a : list) {
if (!exclude.contains(a.annotationType())) {
tmp.add(a);
}
}
}
annotations = tmp.toArray(new Annotation[0]);
}
// 循環(huán)結(jié)束之后,ServiceAopConfig直接和間接標(biāo)注的所有注解就都解析出來了
for (Annotation annotation : annotationList) {
System.out.println(annotation);
}
}
AnnotatedTypeMetadata接口和StandardAnnotationMetadata類
上文介紹了,spring是使用(AnnotatedTypeMetadata)metadata.isAnnotated(Conditional.class.getName())來判斷組件被@Conditional注解標(biāo)注的。
public interface AnnotatedTypeMetadata {
/**
* Return annotation details based on the direct annotations of the underlying element.
* @return merged annotations based on the direct annotations
* @since 5.2
*/
MergedAnnotations getAnnotations();
/**
* Determine whether the underlying element has an
* annotation or meta-annotation of the given type defined.
* @return whether a matching annotation is defined
*/
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}
// ...
}
在我們分析的場景,此處使用的是StandardAnnotationMetadata實(shí)現(xiàn)類。StandardAnnotationMetadata實(shí)現(xiàn)類getAnnotations()返回TypeMappedAnnotations類型對(duì)象。
TypeMappedAnnotations類isPresent方法:
public boolean isPresent(String annotationType) {
if (this.annotationFilter.matches(annotationType)) {
return false;
}
// 在scan方法中
return Boolean.TRUE.equals(scan(annotationType,
IsPresent.get(this.repeatableContainers, this.annotationFilter, false)));
}
private <C, R> R scan(C criteria, AnnotationsProcessor<C, R> processor) {
if (this.annotations != null) {
R result = processor.doWithAnnotations(criteria, 0, this.source, this.annotations);
return processor.finish(result);
}
if (this.element != null && this.searchStrategy != null) {
// 執(zhí)行到這里
return AnnotationsScanner.scan(criteria, this.element, this.searchStrategy, processor);
}
return null;
}
AnnotationsScanner.scan方法:
static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
AnnotationsProcessor<C, R> processor) {
R result = process(context, source, searchStrategy, processor);
return processor.finish(result);
}
// 層層調(diào)用到processElement方法
private static <C, R> R processElement(C context, AnnotatedElement source,
AnnotationsProcessor<C, R> processor) {
try {
R result = processor.doWithAggregate(context, 0);
// 繼續(xù)調(diào)用processor.doWithAnnotations方法
// 這里的processor是TypeMappedAnnotations.IsPresent類型對(duì)象
return (result != null ? result : processor.doWithAnnotations(
context, 0, source, getDeclaredAnnotations(source, false)));
} catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(source, ex);
}
return null;
}
TypeMappedAnnotations.IsPresent類doWithAnnotations方法:
public Boolean doWithAnnotations(Object requiredType, int aggregateIndex,
Object source, Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (annotation != null) {
Class<? extends Annotation> type = annotation.annotationType();
if (type != null && !this.annotationFilter.matches(type)) {
if (type == requiredType || type.getName().equals(requiredType)) {
return Boolean.TRUE;
}
Annotation[] repeatedAnnotations =
this.repeatableContainers.findRepeatedAnnotations(annotation);
if (repeatedAnnotations != null) {
Boolean result = doWithAnnotations(
requiredType, aggregateIndex, source, repeatedAnnotations);
if (result != null) {
return result;
}
}
if (!this.directOnly) {
// 這里會(huì)進(jìn)行遞歸解析
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(type);
for (int i = 0; i < mappings.size(); i++) {
AnnotationTypeMapping mapping = mappings.get(i);
if (isMappingForType(mapping, this.annotationFilter, requiredType)) {
return Boolean.TRUE;
}
}
}
}
}
}
return null;
}
AnnotationTypeMappings.forAnnotationType方法:
static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType) {
return forAnnotationType(annotationType, AnnotationFilter.PLAIN);
}
static AnnotationTypeMappings forAnnotationType(
Class<? extends Annotation> annotationType, AnnotationFilter annotationFilter) {
return forAnnotationType(annotationType, RepeatableContainers.standardRepeatables(), annotationFilter);
}
static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
return new AnnotationTypeMappings(repeatableContainers, annotationFilter, annotationType);
}
AnnotationTypeMappings對(duì)象:
private AnnotationTypeMappings(RepeatableContainers repeatableContainers,
AnnotationFilter filter, Class<? extends Annotation> annotationType) {
this.repeatableContainers = repeatableContainers;
this.filter = filter;
this.mappings = new ArrayList<>();
addAllMappings(annotationType);
this.mappings.forEach(AnnotationTypeMapping::afterAllMappingsSet);
}
private void addAllMappings(Class<? extends Annotation> annotationType) {
Deque<AnnotationTypeMapping> queue = new ArrayDeque<>();
addIfPossible(queue, null, annotationType, null);
// 遞歸解析
while (!queue.isEmpty()) {
AnnotationTypeMapping mapping = queue.removeFirst();
this.mappings.add(mapping);
addMetaAnnotationsToQueue(queue, mapping);
}
}
private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source) {
Annotation[] metaAnnotations =
AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);
// ...
}
static Annotation[] getDeclaredAnnotations(AnnotatedElement source, boolean defensive) {
boolean cached = false;
Annotation[] annotations = declaredAnnotationCache.get(source);
if (annotations != null) {
cached = true;
} else {
// 這里使用java反射api獲取類標(biāo)注的注解
annotations = source.getDeclaredAnnotations();
if (annotations.length != 0) {
// ...
}
}
if (!defensive || annotations.length == 0 || !cached) {
return annotations;
}
return annotations.clone();
}
OnPropertyCondition類
class OnPropertyCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 獲取所有的@ConditionalOnProperty注解屬性
List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
List<ConditionMessage> noMatch = new ArrayList<>();
List<ConditionMessage> match = new ArrayList<>();
// 遍歷@ConditionalOnProperty注解屬性
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment());
(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
}
if (!noMatch.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
}
return ConditionOutcome.match(ConditionMessage.of(match));
}
private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes,
PropertyResolver resolver) {
Spec spec = new Spec(annotationAttributes);
List<String> missingProperties = new ArrayList<>();
List<String> nonMatchingProperties = new ArrayList<>();
// 這里在匹配env參數(shù)
// Spec類封裝了prefix, havingValue, names, matchIfMissing等配置
// collectProperties方法將env參數(shù)與prefix, havingValue, names, matchIfMissing等進(jìn)行匹配
spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
if (!missingProperties.isEmpty()) {
return ConditionOutcome.noMatch(...);
}
if (!nonMatchingProperties.isEmpty()) {
return ConditionOutcome.noMatch(...);
}
return ConditionOutcome
.match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched"));
}
}
public abstract class SpringBootCondition implements Condition {
@Override
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String classOrMethodName = getClassOrMethodName(metadata);
try {
// 此處需要子類實(shí)現(xiàn)
ConditionOutcome outcome = getMatchOutcome(context, metadata);
logOutcome(classOrMethodName, outcome);
recordEvaluation(context, classOrMethodName, outcome);
return outcome.isMatch();
} catch (NoClassDefFoundError ex) {
throw new IllegalStateException("", ex);
} catch (RuntimeException ex) {
throw new IllegalStateException("", ex);
}
}
public abstract ConditionOutcome getMatchOutcome(
ConditionContext context, AnnotatedTypeMetadata metadata);
}
(Spec)spec.collectProperties方法:
private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) {
for (String name : this.names) {
String key = this.prefix + name;
if (resolver.containsProperty(key)) {
if (!isMatch(resolver.getProperty(key), this.havingValue)) {
nonMatching.add(name);
}
} else {
if (!this.matchIfMissing) {
missing.add(name);
}
}
}
}
到此這篇關(guān)于Spring @Conditional注解從源碼層講解的文章就介紹到這了,更多相關(guān)Spring @Conditional注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用springmvc的controller層獲取到請(qǐng)求的數(shù)據(jù)方式
這篇文章主要介紹了使用springmvc的controller層獲取到請(qǐng)求的數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
為spring get請(qǐng)求添加自定義的參數(shù)處理操作(如下劃線轉(zhuǎn)駝峰)
這篇文章主要介紹了為spring get請(qǐng)求添加自定義的參數(shù)處理操作(如下劃線轉(zhuǎn)駝峰),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Map集合中獲取key-value值的實(shí)現(xiàn)方法
這篇文章主要介紹了Map集合中獲取key-value值的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Java給實(shí)體每一個(gè)字段賦默認(rèn)值詳細(xì)代碼示例
這篇文章主要給大家介紹了關(guān)于Java給實(shí)體每一個(gè)字段賦默認(rèn)值的相關(guān)資料,在編程過程中有時(shí)會(huì)出現(xiàn)這樣一種情況,在查詢無結(jié)果時(shí)我們需要給實(shí)體賦默認(rèn)值,需要的朋友可以參考下2023-09-09
SpringBoot整合Druid數(shù)據(jù)庫連接池的方法
Druid是Java語言中最好的數(shù)據(jù)庫連接池。Druid能夠提供強(qiáng)大的監(jiān)控和擴(kuò)展功能。這篇文章主要介紹了SpringBoot整合Druid數(shù)據(jù)庫連接池的方法,需要的朋友可以參考下2020-07-07

