在了解ConfigurationCondition 接口以前,先经过一个示例来了解一下@Conditional 和 Condition。(你也能够经过 https://www.cnblogs.com/cxuanBlog/p/10960575.html 详细了解)html
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cxuan.configuration</groupId> <artifactId>configuration-condition</artifactId> <version>0.0.1-SNAPSHOT</version> <name>configuration-condition</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring.version>4.3.13.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
IfBeanAExistsCondition
类,该类继承了Condition接口,提供某些注册条件的逻辑public class IfBeanAExistsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { boolean IfContainsbeanA = context.getBeanFactory().containsBeanDefinition("beanA"); return IfContainsbeanA; } }
Condition是一个接口,里面只有一个方法就是matches,上述代表若是ConditionContext的beanFactory包括名称为beanA的bean就返回true,不然返回false不进行注册。java
ConfigurationConditionApplication
类,注册两个Bean分别为BeanA和BeanB,BeanB的注册条件是BeanA首先进行注册,采用手动注册和刷新的方式。详见https://www.cnblogs.com/cxuanBlog/p/10958307.html,具体代码以下:public class ConfigurationConditionApplication { private static void loadContextAndVerifyBeans(Class...classToRegistry){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(classToRegistry); context.refresh(); System.out.println("Has BeanA? " + context.containsBean("beanA")); System.out.println("Has BeanB? " + context.containsBean("beanB")); } public static void main(String[] args) { loadContextAndVerifyBeans(BeanA.class); loadContextAndVerifyBeans(BeanA.class,BeanB.class); loadContextAndVerifyBeans(BeanB.class); loadContextAndVerifyBeans(BeanB.class,BeanA.class); } } @Configuration() class BeanA{} @Conditional(IfBeanAExistsCondition.class) @Configuration() class BeanB{}
输出结果:spring
... Has BeanA? true Has BeanB? false ... Has BeanA? true Has BeanB? true ... Has BeanA? false Has BeanB? false ... Has BeanA? true Has BeanB? false
来解释一下上面的输出结果,第一次只注册了一个BeanA的bean,@Configuration标注的BeanA默认注册的definitionName为beanA,首字母小写。apache
第二次同时传入了BeanA.class 和 BeanB.class, 因为BeanB的注解上标明@Conditional(IfBeanAExistsCondition.class)表示的是注册BeanA以后才会注册BeanB,因此注册了beanA,由于beanA被注册了,因此同时也就注册了beanB。maven
第三次只传入了BeanB.class,由于没有注册BeanA和BeanB,因此两次输出都是false。ide
第四次先传入了BeanB.class,后又传入了BeanA.class,根据加载顺序来看,BeanB.class 首先被加载,而后是BeanA.class 被加载,BeanB被加载的时候BeanA.class 尚未被注入,以后BeanA才会注入,因此输出的结果是true和false。spring-boot
上述例子能够把BeanA和BeanB类放入ConfigurationConditionApplication中,相似测试
public class ConfigurationConditionApplication { @Configuration() static class BeanA{} @Conditional(IfBeanAExistsCondition.class) @Configuration() static class BeanB{} }可是须要把BeanA和BeanB定义为静态类,由于静态类与外部类无关可以独立存在,若是定义为非静态的,启动会报错。ui
ConfigurationCondition接口是Spring4.0提供的注解。位于org.springframework.context.annotation包内,继承于Condition接口。Condition接口和@Configuration以及@Conditional接口为bean的注册提供更细粒度的控制,容许某些Condition在匹配时根据配置阶段进行调整。code
public interface ConfigurationCondition extends Condition { // 评估condition返回的ConfigurationPhase ConfigurationPhase getConfigurationPhase(); // 能够评估condition的各类配置阶段。 enum ConfigurationPhase { // @Condition 应该被评估为正在解析@Configuration类 // 若是此时条件不匹配,则不会添加@Configuration 类。 PARSE_CONFIGURATION, // 添加常规(非@Configuration)bean时,应评估@Condition。Condition 将不会阻止@Configuration 类 // 添加。在评估条件时,将解析全部@Configuration REGISTER_BEAN } }
getConfigurationPhase()方法返回ConfigurationPhase 的枚举。枚举类内定义了两个enum,PARSE_CONFIGURATION 和 REGISTER_BEAN,表示不一样的注册阶段。
咱们如今对condition实现更细粒度的控制,实现了ConfigurationCondition接口,咱们如今须要实现getConfigurationPhase()方法得到condition须要评估的阶段。
IfBeanAExistsConfigurationCondition
类,实现了ConfigurationCondition接口,分别返回ConfigurationPhase.REGISTER_BEAN 和 ConfigurationPhase.PARSE_CONFIGURATION 阶段。public class IfBeanAExistsConfigurationCondition implements ConfigurationCondition { @Override public ConfigurationPhase getConfigurationPhase() { return ConfigurationPhase.REGISTER_BEAN; } // @Override // public ConfigurationPhase getConfigurationPhase() { // return ConfigurationPhase.PARSE_CONFIGURATION; // } @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return context.getBeanFactory().containsBeanDefinition("beanA"); } }
SpringConfigurationConditionExample
类,与上述测试类基本相同,就是把@Conditional 换为了@Conditional(IfBeanAExistsConfigurationCondition.class)测试类启动,输出结果
... Has BeanA? true Has BeanB? false ... Has BeanA? true Has BeanB? true ... Has BeanA? false Has BeanB? false ... Has BeanA? true Has BeanB? true
也就是说,若是返回的是PARSE_CONFIGURATION阶段的话,不会阻止@Configuration的标记类的注册顺序,啥意思呢?
第一个结果,只注册了BeanA,由于只有BeanA加载。
第二个结果,注册了BeanA和BeanB,由于BeanA和BeanB都被加载
第三个结果,由于BeanB注册的条件是BeanA注册,由于BeanA没有注册,因此BeanB不会注册
第四个结果,不论BeanA和BeanB的加载顺序如何,都会直接进行注册。