Spring Boot 进阶-深入了解SpringBoot条件注解
在之前的文章中我们了解了关于@Conditional注解的使用,并且通过一个根据操作系统不同注入不同的Bean对象的例子来介绍了@Conditional注解的用法。那么接下来我们就来深入探索一下条件注入究竟是在什么时候被执行的,又是有什么样的加载顺序呢?
条件判断的执行时机
Spring Boot 中的条件注入一般是在两个阶段执行,一个是在配置类解析的阶段,一个是在Bean对象注入阶段。
- 配置类解析阶段:这个阶段会在容器中得到一批的配置类信息,这些配置类主要是用来描述那些Bean需要被注入到容器中,并且这些注入的Bean对象之间的依赖是什么,同时在这配置类中会将一些配置文件中的配置的值加载到其中。所以在这个阶段根据不同的条件来实现不同的条件注入是可以进行的。
- Bean注册的阶段:将配置类解析完成之后,就知道那些Bean对象需要被注册到容器中,就可以根据这些需要注入到容器中的Bean对象的条件根据条件判断来进行容器注入控制操作。
需要注意的是Spring Boot 默认是在配置类解析阶段进行控制的,因为在配置类解析的阶段,很多的判断条件就已经可以获取到了。就可以对注入到容器中的对象根据具体的条件来进行控制了。而不需要等到Bean注入的阶段再进行控制。
当然这也不是绝对的在Spring Boot中提供了ConfigurationCondition 这个接口可以用来自定义执行的阶段,例如@ConditionalOnMissingBean这个注解,它的意思就是在容器中没有对应的Bean对象的时候才会注入,这个时候就需要在Bean注入的时候进行判断,所以这个注解是需要等到Bean注入的时候才能从容器中判断是否存在对应的Bean对象。
这里就有人问了,这两个阶段有什么不同么?
其实这个很容易理解,在配置解析的时候只是将一些需要配置的规则以及需要配置解析的配置类进行了加载,这个时候Bean对象还没有被注入到容器中,能被条件约束的就是一些前置的判断依据,而至于容器中到底有什么对象,还需要等到Bean对象注册阶段,才能知道。所以说对于有些条件判断可以在配置阶段被检查到,但是有些条件判断只能等到Bean注入的时候。
下面我们就来看看ConfigurationCondition注解
ConfigurationCondition接口
这个接口继承了Condition接口并且新增了getConfigurationPhase(),代码如下
public interface ConfigurationCondition extends Condition {
/**
* Return the {@link ConfigurationPhase} in which the condition should be evaluated.
*/
// 用来判断是在配置类解析的时候进行条件判断还是在Bean创建的时候进行条件判断
ConfigurationPhase getConfigurationPhase();
/**
* The various configuration phases where the condition could be evaluated.
*/
enum ConfigurationPhase {
/**
* The {@link Condition} should be evaluated as a {@code @Configuration}
* class is being parsed.
* <p>If the condition does not match at this point, the {@code @Configuration}
* class will not be added.
*/
// 配置类阶段入,如果条件为false,则配置类将不会被解析
PARSE_CONFIGURATION,
/**
* The {@link Condition} should be evaluated when adding a regular
* (non {@code @Configuration}) bean. The condition will not prevent
* {@code @Configuration} classes from being added.
* <p>At the time that the condition is evaluated, all {@code @Configuration}
* classes will have been parsed.
*/
// Bean注册阶段,如果为false,Bean将不会被注册
REGISTER_BEAN
}
}
这个接口在需要指定执行阶段的时候就可以被实现,例如在有些场景中,某个Bean对象需要根据是否存在另一个Bean对象的时候才能被注入,这个时候就在Bean注入的阶段进行调用。也就是之前讲过的类似于@ConditionalOnMissingBean 的注解。
这里我们来看一下这个使用原理,通过分析一下@ConditionalOnMissingBean注解的源码来分析一下,代码如下,这里我们先不管这注解有那些属性,只是来分析一下如何修改判断条件的阶段。
@Target({
ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented