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. Spring MVC @PathVariable 特殊字符

    1.问题 SpringMVC项目中通过下面的URL进行GET请求.当version有多个小数点的时候.如version为1.0.1008.后台通过@PathVariable来获取version等于1. ...

  2. Number String(hdu 4055)

    题意:给定一个字符串,I表示本字符要比前一个字符大,D表示本字符要不前一个字符小,?可大可小,问1~n的所有排列中,有多少满足条件 /* dp方程的设定比较显然,dp[i][j]表示选了i个元素,最后 ...

  3. 洛谷P2114起床困难综合征

    从高位到低位按位枚举,贪心.如果该位填1比填0结果优且填1不会超出m限制,那就填1,否则填0 /*by SilverN*/ #include<iostream> #include<c ...

  4. 洛谷 P1362 兔子数

    题目描述 设 S(N ) 表示 N 的各位数字之和,如 S(484) = 4+8+4 = 16, S(22) = 2+2 = 4.如果一个正整数满足 S(x*x) = S(x) *S(x),我们称之为 ...

  5. [LeetCode] Add Two Numbers 链表

    You are given two linked lists representing two non-negative numbers. The digits are stored in rever ...

  6. HDU 1223 还是畅通过程【最小生成树模板】

    还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  7. Codeforces 777C Alyona and Spreadsheet(思维)

    题目链接 Alyona and Spreadsheet 记a[i][j]为读入的矩阵,c[i][j]为满足a[i][j],a[i - 1][j], a[i - 2][j],......,a[k][j] ...

  8. CentOS 6.9编译安装Python-2.7.14(python升级)

    参考 Python官网:https://www.python.org/ 阿里云 https://www.aliyun.com/jiaocheng/517192.html 一.查看CentOS版本和系统 ...

  9. codevs——1576 最长严格上升子序列(序列DP)

     时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 给一个数组a1, a2 ... an,找到最长的上升降子序列 ...

  10. google搜索打不开?提供 国内几个给力的服务器

    http://203.208.46.145/ 这是北京的机器,快到飞起来. http://74.125.224.232/, 屡试不爽 用编辑器打开C:\WINDOWS\system32\drivers ...