SpringBoot注解@ConditionalOnClass底层源码实现

目录
  • @ConditionalOnClass的底层源码实现
    • ConditionOutcome对象
    • ClassNameFilter.MISSING判断某类是否不存在

@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的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot底层注解超详细介绍

    目录 1. @Configuration 2. @bean 3. @Import 4. @Conditional条件装配 5. 配置绑定 SpringBoot自动配置原理(源码分析) 1. @Configuration —— 放在类前注释 用于表示配置类,配置类也是一个组件 @Configuration(proxyBeanMethods = true) // 配置类 == 配置文件 public class MyConfig { } 通过 proxyBeanMethods 很好的解决了组件依赖的

  • SpringBoot2底层注解@Configuration配置类详解

    目录 SpringBoot2底层注解@Configuration配置类 一.配置类 二.配置类本身也是组件 三.proxyBeanMethods 属性 有组件依赖的场景 SpringBoot2底层注解@Configuration配置类 一.配置类 @Configuration这个注解作用就是告诉 springboot 这是一个配置类. 这个配置已经不陌生了,在之前 spring 相关的使用全注解方式时,就使用到了配置类. 在配置类里,可以使用@Bean标记在方法上,给容器注册组件,默认也是单实例

  • 详解如何实现SpringBoot的底层注解

    一.@Configuration注解 1.基本使用 自定义配置类 /** * 1.@Configuration 告诉SpringBoot这是一个配置类,相当于一个xml配置文件 * * 2.配置类里面使用 @Bean 标注在方法上 来给容器注册组件,默认是单实例的 * * 3.配置类本身也是一个组件 */ @Configuration(proxyBeanMethods = true) public class MyConfig { @Bean public User user01(){ retu

  • SpringBoot2底层注解@Import用法详解

    目录 SpringBoot2注解@Import @Import 导入组件 用法 验证 SpringBoot2注解@Import 上一篇中了解到了@Configuration,可以注册组件.除此之外,还有许多注解也可以,用法跟之前学习 spring 的时候一样.比如,@Bean.@Component.@Controller.@Service.@Repository等. 这篇介绍另外一种给容器添加组件的方法:@Import注解,给容器中导入组件. @Import 导入组件 用法 @Import的用法

  • SpringBoot请求处理之常用参数注解介绍与源码分析

    目录 1.注解 2.注解生效相关源码分析 3.Servlet API 4.复杂参数 5.自定义参数 6.类型转换器Converters 1.注解 @PathVariable:将请求url中的占位符参数与控制器方法入参绑定起来(Rest风格请求) @RequestHeader:获取请求头中的参数,通过指定参数 value 的值来获取请求头中指定的参数值 @ModelAttribute:两种用法 用在参数上,会将客户端传递过来的参数按名称注入到指定对象中,并且会将这个对象自动加入ModelMap中,

  • SpringBoot 启动方法run()源码解析

    入口 通常一个简单的SpringBoot基础项目我们会有如下代码 @SpringBootApplication @RestController @RequestMapping("/") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 值得关注的有SpringApplication.run以及注解@

  • SpringBoot静态资源配置原理(源码分析)

    前言: 我们都知道,SpringBoot启动会默认加载很多xxxAutoConfiguration类(自动配置类) 其中SpringMVC的大都数功能都集中在WebMvcAutoConfiguration类中,根据条件ConditionalOnxxx注册类对象:WebMvcAutoConfiguration满足以下ConditionalOnxxx条件,类是生效的,并把其对象注册到容器中. 那WebMvcAutoConfiguration生效给容器中配置了什么呢? WebMvcAutoConfig

  • Spring AOP底层源码详解

    ProxyFactory的工作原理 ProxyFactory是一个代理对象生产工厂,在生成代理对象之前需要对代理工厂进行配置.ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术. // config就是ProxyFactory对象 // optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface if (config.isOptimize() || config.isProxy

  • springboot自动装配的源码与流程图

    前言 在使用SpringBoot开发项目中,遇到一些 XXX-XXX-starter,例如mybatis-plus-boot-starter,这些包总是能够自动进行配置, 减少了开发人员配置一些项目配置的时间,让开发者拥有更多的时间用于开发的任务上面.下面从源码开始. 正文 SpringBoot版本:2.5.3 从@SpringBootApplication进入@EnableAutoConfiguration 然后进入AutoConfigurationImportSelector @Target

  • 详谈HashMap和ConcurrentHashMap的区别(HashMap的底层源码)

    HashMap本质是数组加链表,根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap在HashMap的基础上将数据分为多个segment,默认16个,然后每次操作对一个segment加锁,避免多线程锁的几率,提高并发效率. 1. HashMap的数据结构 HashMap底层就是一个数组结构,数组中存放的是一个Entry对象,如果产生的hash冲突,这时候该位置存储的就是一个链表了. HashMap中En

  • Spring-boot 2.3.x源码基于Gradle编译过程详解

    spring Boot源码编译 1. git上下拉最新版的spring Boot 下载:git clone git@github.com:spring-projects/spring-boot.git,建议下载release版本,不会出现奇奇怪怪的错误 2.修改下载源, gradle\wrapper中的配置文件 gradle-wrapper.properties distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists #d

  • SpringBoot拦截器以及源码详析

    目录 1.拦截器是什么 2.自定义拦截器 2.1 编写拦截器 2.2 注册和配置拦截器 3.拦截器原理 3.1 找到可以处理请求的handler以及handler的所有拦截器 3.2 执行拦截器的preHandle方法 3.3 执行目标方法 3.4 执行拦截器的postHandle方法 3.5 执行拦截器的afterCompletion方法 3.6 异常处理 4.总结 1.拦截器是什么 java里的拦截器(Interceptor)是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一

  • Java同步锁Synchronized底层源码和原理剖析(推荐)

    目录 1 synchronized场景回顾 2 反汇编寻找锁实现原理 3 synchronized虚拟机源码 3.1 HotSpot源码Monitor生成 3.2 HotSpot源码之Monitor竞争 3.3 HotSpot源码之Monitor等待 3.4 HotSpot源码之Monitor释放 1 synchronized场景回顾 目标:synchronized回顾(锁分类–>多线程)概念synchronized:是Java中的关键字,是一种同步锁.Java中锁分为以下几种:乐观锁.悲观锁(

  • 通过底层源码理解YOLOv5的Backbone

    目录 YOLOv5的Backbone设计 1 Backbone概览及参数 1.1 Param 1.2 backbone 1.3 Exp 2 Backbone组成 3.1 CBS 3.2 CSP/C3 3.2.1 CSP结构 3.2.2 Bottleneck 3.3 SSPF YOLOv5s的Backbone总览 总结 YOLOv5的Backbone设计 在上一篇文章<YOLOV5的anchor设定>中我们讨论了anchor的产生原理和检测过程,对YOLOv5的网络结构有了大致的了解.接下来,我

随机推荐