前言
问题
主要是发现了一个问题,在看springboot 源码的时候。
这种飘红的代码就没有这个类,但项目依然可以启动起来。为什么?
先看下@ConditionalOnClass
@ConditionalOnClass
这个注解有一个基础注解@Conditional
,还可以看到一个OnClassCondition.class
,这个属性是一个数组。
Conditional
这个接口,SpringBootCondition
就实现了这个接口来对Contional
注解进行处理
- 下面是这几个核心类的关系
Spring如何判断一个类是否加载呢
- 先给出一个加载链路
org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)
org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])
org.springframework.boot.SpringApplication#run(java.lang.String...)
org.springframework.boot.SpringApplication#prepareContext
org.springframework.boot.SpringApplication#load
org.springframework.boot.BeanDefinitionLoader#load()
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Object)
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Class<?>)
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class<?>)
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
org.springframework.context.annotation.ConditionEvaluator#shouldSkip(org.springframework.core.type.AnnotatedTypeMetadata)
org.springframework.context.annotation.ConditionEvaluator#shouldSkip(org.springframework.core.type.AnnotatedTypeMetadata, org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase)
org.springframework.context.annotation.Condition#matches
org.springframework.boot.autoconfigure.condition.SpringBootCondition#matches(org.springframework.context.annotation.ConditionContext, org.springframework.core.type.AnnotatedTypeMetadata)
org.springframework.boot.autoconfigure.condition.SpringBootCondition#getMatchOutcome
org.springframework.boot.autoconfigure.condition.OnClassCondition#getMatchOutcome
org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition#filter
org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.ClassNameFilter#matches
org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition.ClassNameFilter#isPresent
核心流程
ConditionEvaluator#shouldSkip
这个方法主要是判断类是否要跳过加载。
SpringBootCondition#matches
是判断符合条件
3. 看下SpringBootCondition#getMatchOutcome
看到这里我们就可以知道ConditionalOnClass
注解里的类属性是通过类加载器和forName
的方法判断类路径上是否有该类,如果类路径上有该类则加载成功,也就是能够成功匹配,成功匹配后SpringBoot
就会把ConditionalOnClass
注解标记的类加入到容器中。
这里可以看出,没有加载成功的spring已经把异常给catch住了,只是没有往上抛出。