欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring @Conditional注解從源碼層講解

 更新時(shí)間:2023年01月10日 08:45:49   作者:xuguofeng2016  
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件給容器注冊(cè)bean,這篇文章主要介紹了Spring @Conditional注解示例詳細(xì)講解,需要的朋友可以參考下

本文通過(guò)閱讀@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)證

下文將展開(kāi)說(shuō)明這4個(gè)步驟。

判斷目標(biāo)組件是否被Conditional標(biāo)注

AnnotatedTypeMetadata中封裝了目標(biāo)組件的注解元信息,可以通過(guò)他獲取到目標(biāo)組件的注解相關(guān)信息,比如是否被某個(gè)注解標(biāo)注、某個(gè)注解的屬性等。

metadata.isAnnotated(Conditional.class.getName())

AnnotatedTypeMetadata中定義了該方法的實(shí)現(xiàn)方式:

default boolean isAnnotated(String annotationName) {
    // 通過(guò)MergedAnnotations來(lái)獲取注解標(biāo)注狀態(tài)
	return getAnnotations().isPresent(annotationName);
}

我們?cè)谥暗摹禨pring-@Bean注解源碼分析》中介紹過(guò),此處使用的是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()方法來(lái)實(shí)現(xiàn)的,此處不展開(kāi)說(shuō)明,后續(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)) // 過(guò)濾
			.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ì)通過(guò)遞歸方式使用java反射api從組件類getAnnotations以便獲取到所有的注解信息,代碼較多,此處不展開(kāi)記錄。

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注解,此處不展開(kāi)記錄了
		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獲取排序
            // 在此處場(chǎng)景下調(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())來(lái)判斷組件被@Conditional注解標(biāo)注的。但是@Conditional標(biāo)注在@ConditionalOnProperty注解上,使用普通的(Class)clazz.isAnnotationPresent(Conditional.class)方式無(wú)法判斷,那么metadata.isAnnotated方法是如何判斷的呢?

從上面@ConditionalOnProperty注解定義可以知道,目標(biāo)組件類標(biāo)注了@ConditionalOnProperty注解,@ConditionalOnProperty注解又標(biāo)注了@Conditional注解,這顯然是一個(gè)遞歸,只有從目標(biāo)組件類開(kāi)始遞歸解析,就可以解析出目標(biāo)組件類上的所有注解,以下是一個(gè)我自己編寫的簡(jiǎn)單示例:

@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)注的所有注解就都解析出來(lái)了
  for (Annotation annotation : annotationList) {
    System.out.println(annotation);
  }
}

AnnotatedTypeMetadata接口和StandardAnnotationMetadata類

上文介紹了,spring是使用(AnnotatedTypeMetadata)metadata.isAnnotated(Conditional.class.getName())來(lái)判斷組件被@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);
	}
    // ...
}

在我們分析的場(chǎng)景,此處使用的是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)文章

  • 教你怎么用IDEA快速生成注釋文檔

    教你怎么用IDEA快速生成注釋文檔

    這篇文章主要介紹了教你怎么用IDEA快速生成注釋文檔,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)IDEA操作的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • 詳細(xì)介紹Java內(nèi)存泄露原因

    詳細(xì)介紹Java內(nèi)存泄露原因

    詳細(xì)介紹Java內(nèi)存泄露原因,需要的朋友可以參考一下
    2013-05-05
  • java網(wǎng)絡(luò)編程之群聊功能

    java網(wǎng)絡(luò)編程之群聊功能

    這篇文章主要為大家詳細(xì)介紹了java網(wǎng)絡(luò)編程之群聊功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 使用springmvc的controller層獲取到請(qǐng)求的數(shù)據(jù)方式

    使用springmvc的controller層獲取到請(qǐng)求的數(shù)據(jù)方式

    這篇文章主要介紹了使用springmvc的controller層獲取到請(qǐng)求的數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java中比較抽象類與接口的異同

    Java中比較抽象類與接口的異同

    大家好,本篇文章主要講的是Java中比較抽象類與接口的異同,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 為spring get請(qǐng)求添加自定義的參數(shù)處理操作(如下劃線轉(zhuǎn)駝峰)

    為spring get請(qǐng)求添加自定義的參數(shù)處理操作(如下劃線轉(zhuǎn)駝峰)

    這篇文章主要介紹了為spring get請(qǐng)求添加自定義的參數(shù)處理操作(如下劃線轉(zhuǎn)駝峰),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • Java多線程 ThreadLocal原理解析

    Java多線程 ThreadLocal原理解析

    這篇文章主要介紹了Java多線程 ThreadLocal原理,ThreadLoal 變量,線程局部變量,同一個(gè) ThreadLocal 所包含的對(duì)象,在不同的 Thread 中有不同的副本,下面文章也是圍繞Java多線程 ThreadLocal展開(kāi)內(nèi)容,需要的朋友可以參考一下
    2021-10-10
  • Map集合中獲取key-value值的實(shí)現(xiàn)方法

    Map集合中獲取key-value值的實(shí)現(xiàn)方法

    這篇文章主要介紹了Map集合中獲取key-value值的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java給實(shí)體每一個(gè)字段賦默認(rèn)值詳細(xì)代碼示例

    Java給實(shí)體每一個(gè)字段賦默認(rèn)值詳細(xì)代碼示例

    這篇文章主要給大家介紹了關(guān)于Java給實(shí)體每一個(gè)字段賦默認(rèn)值的相關(guān)資料,在編程過(guò)程中有時(shí)會(huì)出現(xiàn)這樣一種情況,在查詢無(wú)結(jié)果時(shí)我們需要給實(shí)體賦默認(rèn)值,需要的朋友可以參考下
    2023-09-09
  • SpringBoot整合Druid數(shù)據(jù)庫(kù)連接池的方法

    SpringBoot整合Druid數(shù)據(jù)庫(kù)連接池的方法

    Druid是Java語(yǔ)言中最好的數(shù)據(jù)庫(kù)連接池。Druid能夠提供強(qiáng)大的監(jiān)控和擴(kuò)展功能。這篇文章主要介紹了SpringBoot整合Druid數(shù)據(jù)庫(kù)連接池的方法,需要的朋友可以參考下
    2020-07-07

最新評(píng)論