首頁 > 軟體

SpringBoot註解@ConditionalOnClass底層原始碼實現

2023-11-01 18:00:41

@ConditionalOnClass的底層原始碼實現

在SpringBoot中,支援了很多種條件註解,@ConditionalOnClass註解就是其中之一,而且及其重要,它主要是用來判斷該註解所指定的某個類或某些類,是否在ClassPath中存在,如果存在則符合條件,如果不存在則不符合。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
	Class<?>[] value() default {};
	String[] name() default {};
}

這是該註解的原始碼,可以通過value和name來指定要判斷的類,而真正執行判斷的邏輯在OnClassCondition類中。

  • OnClassCondition類繼承了FilteringSpringBootCondition類
  • FilteringSpringBootCondition類又繼承了SpringBootCondition類
  • SpringBootCondition類實現了Condition介面

Spring在解析條件註解時,就會呼叫Condition介面的matches()方法,在上面的類繼承關係中,SpringBootCondition類實現了matches()方法,所以會先被呼叫。

ConditionOutcome物件

在matches()方法中,會呼叫getMatchOutcome()方法,並得到ConditionOutcome物件,ConditionOutcome物件就表示條件判斷的結果。

public class ConditionOutcome {
	// 表示條件是否匹配
	private final boolean match;
	// ...
}

getMatchOutcome()方法在SpringBootCondition類中是一個抽象方法,在子類OnClassCondition類中才真正實現了getMatchOutcome()方法,並真正會進行條件判斷。

所以核心就是這個getMatchOutcome()方法,在這個方法中會先獲取@ConditionalOnClass註解的value和name屬性的值,這些值就是待判斷的類名集合。

// 呼叫getCandidates方法
List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
private List<String> getCandidates(AnnotatedTypeMetadata metadata, Class<?> annotationType) {
	MultiValueMap<String, Object> attributes = 
		metadata.getAllAnnotationAttributes(annotationType.getName(), true);
	if (attributes == null) {
		return null;
	}
	List<String> candidates = new ArrayList<>();
	addAll(candidates, attributes.get("value"));
	addAll(candidates, attributes.get("name"));
	return candidates;
}

ClassNameFilter.MISSING判斷某類是否不存在

接下來就會逐個判斷類名集合中的每個類名,判斷邏輯為:利用ClassNameFilter.MISSING來判斷某類是否不存在?

List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter, ClassLoader classLoader) {
	if (CollectionUtils.isEmpty(classNames)) {
		return Collections.emptyList();
	}
	List<String> matches = new ArrayList<>(classNames.size());
	for (String candidate : classNames) {
		if (classNameFilter.matches(candidate, classLoader)) {
			matches.add(candidate);
		}
	}
	return matches;
}

ClassNameFilter.MISSING就是利用ClassLoader來載入類,如果載入到了表示類存在,沒載入到就表示不存在。

protected enum ClassNameFilter {
	// ...
	MISSING {
		@Override
		public boolean matches(String className, ClassLoader classLoader) {
                        // 是否不存在
			return !isPresent(className, classLoader);
		}
	};
	static boolean isPresent(String className, ClassLoader classLoader) {
		if (classLoader == null) {
			classLoader = ClassUtils.getDefaultClassLoader();
		}
		try {
			resolve(className, classLoader);
			return true;
		}
		catch (Throwable ex) {
			return false;
		}
	}
}
protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
	if (classLoader != null) {
		return Class.forName(className, false, classLoader);
	}
	return Class.forName(className);
}

判斷完之後,只要missing集合不為空,那就表示待判斷的類中有類不存在,那就返回條件不匹配的ConditionOutcome物件,否則就返回條件匹配的ConditionOutcome物件。

這就是@ConditionalOnClass註解的核心原始碼流程,期待你的點贊哦。

以上就是SpringBoot註解@ConditionalOnClass底層原始碼實現的詳細內容,更多關於SpringBoot ConditionalOnClass的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com