这个两个阶段有什么不同呢?:其实很简单的,配置类解析阶段只是将需要加载配置类和一些Bean(被@Conditional注解过滤掉之后)收集起来,而Bean注册阶段是将的收集来的Bean和配置类注入到容器中,如果在配置类解析阶段执行Condition接口的matches()接口去判断某些Bean是否存在IOC容器中,这个显然是不行的,因为这些Bean还未注册到容器中。
什么是配置类,有哪些?:类上被@Component、 @ComponentScan、@Import、@ImportResource、@Configuration标注的以及类中方法有@Bean的方法。如何判断配置类,在源码中有单独的方法:org.springframework.context.annotation.ConfigurationClassUtils#isConfigurationCandidate。
ConfigurationCondition接口这个接口相比于@Condition接口就多了一个getConfigurationPhase()方法,可以自定义执行阶段。源码如下:
public interface ConfigurationCondition extends Condition { /** * 条件判断的阶段,是在解析配置类的时候过滤还是在创建bean的时候过滤 */ ConfigurationPhase getConfigurationPhase(); /** * 表示阶段的枚举:2个值 */ enum ConfigurationPhase { /** * 配置类解析阶段,如果条件为false,配置类将不会被解析 */ PARSE_CONFIGURATION, /** * bean注册阶段,如果为false,bean将不会被注册 */ REGISTER_BEAN } }这个接口在需要指定执行阶段的时候可以实现,比如需要根据某个Bean是否在IOC容器中来注入指定的Bean,则需要指定执行阶段为Bean的注册阶段(ConfigurationPhase.REGISTER_BEAN)。
多个Condition的执行顺序@Conditional中的Condition判断条件可以指定多个,默认是按照先后顺序执行,如下:
class Condition1 implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println(this.getClass().getName()); return true; } } class Condition2 implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println(this.getClass().getName()); return true; } } class Condition3 implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println(this.getClass().getName()); return true; } } @Configuration @Conditional({Condition1.class, Condition2.class, Condition3.class}) public class MainConfig5 { }上述例子会依次按照Condition1、Condition2、Condition3执行。
默认按照先后顺序执行,但是当我们需要指定顺序呢?很简单,有如下三种方式:
实现PriorityOrdered接口,指定优先级
实现Ordered接口接口,指定优先级
使用@Order注解来指定优先级
例子如下:
@Order(1) class Condition1 implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println(this.getClass().getName()); return true; } } class Condition2 implements Condition, Ordered { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println(this.getClass().getName()); return true; } @Override public int getOrder() { return 0; } } class Condition3 implements Condition, PriorityOrdered { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println(this.getClass().getName()); return true; } @Override public int getOrder() { return 1000; } } @Configuration @Conditional({Condition1.class, Condition2.class, Condition3.class}) public class MainConfig6 { }根据排序的规则,PriorityOrdered的会排在前面,然后会再按照order升序,最后可以顺序是:Condtion3->Condtion2->Condtion1
Spring Boot中常用的一些注解Spring Boot中大量使用了这些注解,常见的注解如下:
@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:基于SpEL表达式的条件判断。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。