SpringBoot注解@ConditionalOnClass底层源码实现

 更新时间:2023年02月06日 16:35:36   作者:Hoeller  
这篇文章主要为大家介绍了SpringBoot注解@ConditionalOnClass底层源码实现,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

@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的资料请关注脚本之家其它相关文章!

相关文章

  • Spring Security角色继承分析

    Spring Security角色继承分析

    这篇文章主要介绍了Spring Security角色继承分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • JAVA容器集合全面解析(Collection和Map)

    JAVA容器集合全面解析(Collection和Map)

    这篇文章主要介绍了JAVA容器集合全面解析(Collection和Map)本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • 深入理解Java中的HashMap的实现机制

    深入理解Java中的HashMap的实现机制

    这篇文章主要介绍了深入理解Java中的HashMap的实现机制,同时也有助于理解Java中对于哈希函数的相关处理方式,需要的朋友可以参考下
    2015-07-07
  • logback OutputStreamAppender高效日志输出源码解析

    logback OutputStreamAppender高效日志输出源码解析

    这篇文章主要介绍了为大家logback OutputStreamAppender日志输出效率提升示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 关于Java中的CAS如何使用

    关于Java中的CAS如何使用

    这篇文章主要介绍了关于Java中的CAS如何使用,CAS是Compare And Swap(比较并交换)的缩写,是一种非阻塞式并发控制技术,用于保证多个线程在修改同一个共享资源时不会出现竞争条件,从而避免了传统锁机制的各种问题,需要的朋友可以参考下
    2023-09-09
  • java并发编程死锁定义及如何避免死锁

    java并发编程死锁定义及如何避免死锁

    这篇文章主要为大家介绍了java并发编程中死锁的详细说明及如何避免死锁的方法,有需要的朋友可以借鉴参考下希望能够有所帮助,祝大家多多进步
    2022-02-02
  • Java时间类Date类和Calendar类的使用详解

    Java时间类Date类和Calendar类的使用详解

    这篇文章主要介绍了Java时间类Date类和Calendar类的使用详解,需要的朋友可以参考下
    2017-08-08
  • Spring框架中部署log4j.xml的详细步骤

    Spring框架中部署log4j.xml的详细步骤

    Log4j是一个常用的日志记录工具,它可以帮助我们记录应用程序的运行日志并进行灵活的配置,在Spring框架中,我们可以很方便地部署log4j.xml配置文件来管理日志记录,这篇文章主要介绍了Spring框架中部署log4j.xml的详细步骤并提供相应的代码示例,需要的朋友可以参考下
    2023-09-09
  • MyBatisPuls多数据源操作数据源偶尔报错问题

    MyBatisPuls多数据源操作数据源偶尔报错问题

    这篇文章主要介绍了MyBatisPuls多数据源操作数据源偶尔报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • Java多态成员访问的特点是什么?

    Java多态成员访问的特点是什么?

    在上一篇文章中介绍了方法重载和方法重写的区别,但是在多态情况下发现程序的执行结果和我们预期的不太一样,这篇将继续介绍多态场景下,Java成员访问的特点,需要的朋友可以参考下
    2021-06-06

最新评论