一、简介
相信大家在学springBoot自动装配的时候会遇到下面这些条件注解,当存在其指定的条件,才会把对应的bean注入到IOC容器中。本博客旨在揭开其神秘的面纱!
其实说白了,springBoot的这些注解只是针对普通spring框架中@Condition注解的扩展,使其功能更加强大罢了!下面我们以分析@ConditionalOnClass
为例子,简单介绍一下它的实现原理。
二、源码分析
2.1@ConditionalOnClass
的上方标注了@Condition注解,我们只需要看其配置的条件类即可!
2.2通过uml类图可以看到其继承了Condition接口
在父类的SpringBootCondition中实现了核心的matches
方法,其中圈出来的部分是个抽象方法,需要子类自己单独实现,这样我们接着看OnClassCondition#getMatchOutcome
就行了!
2.3接着分析getMatchOutcome
首先我们可以看到OnClassCondition的这个方法的getMatchOutcome
,会处理@ConditionalOnClass、@ConditionalOnMissingClass这两个注解!我们看第一个大if代码块就行!
图中的圈出来的代码就很有意思,底层通过classloader尝试去加载注解配置的类,如果加载异常就说明这个类不存在,于是就放进onMissingClasses
中!
后续逻辑也很清晰明了,有缺损的class那么自然不符合注入条件,那么会返回match=false的ConditionOutcome!
2.4回到父类SpringBootCondition中的matches方法
很显然如果第三步存在缺损的class(onMissingClasses列表不为空),那么就会返回false,告诉spring容器不要注入这个bean
三、普通的Spring怎么处理Condition注解的
二中我们只分析到了SpringBoot中的源码,看到matches方法返回为false,至于为什么这个方法返回为false就不注入这个bean的逻辑还的看普通的spring源码,咱们怀着探索精神也去了解一下:
3.1Spring在启动的时候会自带一个叫ConfigurationClassPostProcessor
的BeanFactory后置处理器
具体调用的时机是在refresh方法中的invokeBeanFactoryPostProcessors
,具体源码我就不带大家追了,直接看ConfigurationClassPostProcessor#processConfigBeanDefinitions
这个方法吧,再这个方法中我们也只需要关心他是怎么处理配置类的,也就是我圈出来的部分!
3.2上图圈出来的部分最后会调用到ConfigurationClassParser#processConfigurationClass
中
其方法的第一行就是处理@Condition
注解的逻辑
3.3接着我们直接看shouldSkip方法
如果shouldSkip
返回为true那么就不放进configurationClasses这个map中后续也不会加载其BeanDefinition,也就不会把这个Bean放入IOC容器中!可以在shouldSkip
中看到调用了Condition的matches方法。matches方法返回为false也就是不满足Condition的条件,shouldSkip
才会返回true!
四、其他条件注解的简单介绍
- 4.1@ConditionalOnBean:底层会通过BeanFactory来尝试获取条件bean是否存在
- 4.2@ConditionalOnProperty:底层会通过Environment获取properties文件中配置的属性的值
- 4.3@ConditionOnJava:这个注解是用java版本来当充当判断条件的,里面比较有意思的是如何获取当前项目的java版本(
JavaVersion#getJavaVersion
),针对老版本的springboot是通过是否存在某个类来判断的,新版本的springboot是通过存在某个类和类方法来进行判断的 - 4.4@ConditionalOnWebApplication:底层是通过是否存在GenericWebApplicationContext这个类以及其作用域有session这个作用域等其他条件来判断出是servlet应用,如果有reactive.HandlerResult这个类加上其他条件来判断是否是Reactive的web应用。