ConfigurationCondition 接口说明

@Conditional 和 Condition

​ 在了解ConfigurationCondition 接口之前,先通过一个示例来了解一下@Conditional 和 Condition。(你也可以通过 https://www.cnblogs.com/cxuanBlog/p/10960575.html 详细了解)

  • 首先新建一个Maven项目(可以使用SpringBoot快速搭建),添加Spring4.0 的pom.xml 依赖
<?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不进行注册。

  • 为了测试Condition是否可用,我们新建一个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{}

输出结果:

...
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,首字母小写。

第二次同时传入了BeanA.class 和 BeanB.class, 由于BeanB的注解上标明@Conditional(IfBeanAExistsCondition.class)表示的是注册BeanA之后才会注册BeanB,所以注册了beanA,因为beanA被注册了,所以同时也就注册了beanB。

第三次只传入了BeanB.class,因为没有注册BeanA和BeanB,所以两次输出都是false。

第四次先传入了BeanB.class,后又传入了BeanA.class,根据加载顺序来看,BeanB.class 首先被加载,然后是BeanA.class 被加载,BeanB被加载的时候BeanA.class 还没有被注入,之后BeanA才会注入,所以输出的结果是true和false。

上述例子可以把BeanA和BeanB类放入ConfigurationConditionApplication中,类似

public class ConfigurationConditionApplication {

@Configuration()
static class BeanA{} @Conditional(IfBeanAExistsCondition.class)
@Configuration()
static class BeanB{} }

但是需要把BeanA和BeanB定义为静态类,因为静态类与外部类无关能够独立存在,如果定义为非静态的,启动会报错。

关于ConfigurationConditon

​ ConfigurationCondition接口是Spring4.0提供的注解。位于org.springframework.context.annotation包内,继承于Condition接口。Condition接口和@Configuration以及@Conditional接口为bean的注册提供更细粒度的控制,允许某些Condition在匹配时根据配置阶段进行调整。

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的加载顺序如何,都会直接进行注册。

  • 如果把REGISTER_BEAN改为**PARSE_CONFIGURATION **,会发现加载顺序第一次一致。

一文了解ConfigurationConditon接口的更多相关文章

  1. springmvc下载一个文档下载接口里的文档

    A提供了一个文件下载的接口,在调用的时候可以直接在前端用a标签来调用 <a href="http://" target="_blank">下载< ...

  2. elasticsearch 第五篇(文档操作接口)

    INDEX API 示例: 1 2 3 4 5 PUT /test/user/1 { "name": "silence", "age": 2 ...

  3. [转]支付宝接口程序、文档及解读(ASP.NET)

    本文转自:http://www.cnblogs.com/blodfox777/archive/2009/11/03/1595223.html 最近需要为网站加入支付宝的充值接口,而目前关于支付宝接口开 ...

  4. 支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url.

    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url. 现支付宝的通知有两类. A服务器通知,对应的参数为notify_url,支付宝通知使用POST方式 B页面跳转通 ...

  5. 三 drf 认证,权限,限流,过滤,排序,分页,异常处理,接口文档,集xadmin的使用

    因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员. python manage.py createsuperuser 创建管理员以后,访问admin站点 ...

  6. drf 生成接口文档

    REST framework可以自动帮助我们生成接口文档.接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 一.安装依赖 REST framewrok生成接口文档 ...

  7. DRF之接口文档以及Xadmin

    1. 自动生成接口文档 REST framework可以自动帮助我们生成接口文档. 接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 1.1. 安装依赖 REST ...

  8. 接口测试之接口api文档的重要性

    接口文档的特点 接口文档,顾名思义就是对接口说明的文档.好的接口文档包含了对接口URL,参数以及输出内容的说明,我们参照接口文档就能编写出一个个的测试用例.而且接口文档详细的话,测试用例编写简单,不会 ...

  9. DRF-自动生成接口文档

    REST framework可以自动帮助我们生成接口文档. 接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 1. 安装依赖 REST framewrok生成接口 ...

随机推荐

  1. pat 甲级 1009. Product of Polynomials (25)

    1009. Product of Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...

  2. 洛谷[P3622] 动物园

    状压DP 发现本题中,每个小朋友是否高兴仅取决于其后五个动物的情况,我们可以用状压DP解决本题 首先已处理 num[i][s] 表示对于位置 i ,状态为 s 时有多少在 s 的同学满意 转移方程很好 ...

  3. 转 vim常用命令总结

    vim常用命令总结 vim 选择文本,删除,复制,粘贴   文本的选择,对于编辑器来说,是很基本的东西,也经常被用到,总结如下: v    从光标当前位置开始,光标所经过的地方会被选中,再按一下v结束 ...

  4. g++的编译选项:-Wl,-rpath=【转】

    转自:http://blog.csdn.net/russule/article/details/7057398 动态链接库 1 生成hello.so g++ -shared hello.cpp -ol ...

  5. Android大神 博客

    https://github.com/yeungeek/awesome-android-person Android大神 受Trinea的开源项目的启发和参考,也准备列一列Android圈里的大神们. ...

  6. 前端js、jQuery实现日期格式化、字符串格式化

    1. js仿后台的字符串的StringFormat方法 在做前端页面时候,经常会对字符串进行拼接处理,但是直接使用字符串拼接,不但影响阅读,而且影响执行效率,且jQuery有没有定义字符串的Strin ...

  7. Codeforces Gym100814 B.Unlucky Teacher (ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (2015) Arab Academy for Science and Technology)

    今日份的训练题解,今天写出来的题没有昨天多,可能是因为有些事吧... 这个题就是老师改卷子,忘带标准答案了,但是他改了一部分卷子,并且确定自己改的卷子没出错,他想从改过的卷子里把标准答案推出来. 因为 ...

  8. angular6安装

    中文 https://www.angular.cn/ 二.下载 1.安装 node.js https://nodejs.org/en/ 2.删除老angular-cli npm uninstall - ...

  9. spring 自定义解析类

    设计配置属性和JavaBean 编写XSD文件 编写NamespaceHandler和BeanDefinitionParser完成解析工作 编写spring.handlers和spring.schem ...

  10. php分页显示文章列表

    <div class="content"> <ul> <?php $querySel = "select * from news where ...