一文了解ConfigurationConditon接口
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接口的更多相关文章
- springmvc下载一个文档下载接口里的文档
A提供了一个文件下载的接口,在调用的时候可以直接在前端用a标签来调用 <a href="http://" target="_blank">下载< ...
- elasticsearch 第五篇(文档操作接口)
INDEX API 示例: 1 2 3 4 5 PUT /test/user/1 { "name": "silence", "age": 2 ...
- [转]支付宝接口程序、文档及解读(ASP.NET)
本文转自:http://www.cnblogs.com/blodfox777/archive/2009/11/03/1595223.html 最近需要为网站加入支付宝的充值接口,而目前关于支付宝接口开 ...
- 支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url.
支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url. 现支付宝的通知有两类. A服务器通知,对应的参数为notify_url,支付宝通知使用POST方式 B页面跳转通 ...
- 三 drf 认证,权限,限流,过滤,排序,分页,异常处理,接口文档,集xadmin的使用
因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员. python manage.py createsuperuser 创建管理员以后,访问admin站点 ...
- drf 生成接口文档
REST framework可以自动帮助我们生成接口文档.接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 一.安装依赖 REST framewrok生成接口文档 ...
- DRF之接口文档以及Xadmin
1. 自动生成接口文档 REST framework可以自动帮助我们生成接口文档. 接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 1.1. 安装依赖 REST ...
- 接口测试之接口api文档的重要性
接口文档的特点 接口文档,顾名思义就是对接口说明的文档.好的接口文档包含了对接口URL,参数以及输出内容的说明,我们参照接口文档就能编写出一个个的测试用例.而且接口文档详细的话,测试用例编写简单,不会 ...
- DRF-自动生成接口文档
REST framework可以自动帮助我们生成接口文档. 接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 1. 安装依赖 REST framewrok生成接口 ...
随机推荐
- Bits
先%SY... 课件链接 求1的个数 以32位整数为例子,最暴力的方法就是一位一位的数,但是这样太不优美... 以下是优美的方法... 这个问题其实就是二进制求和... 我们考虑分治的思想...每一次 ...
- Qualcomm 專業名詞
APSS Application processor subsystem software BAM Bus Access Manager blsp BAM low speed peripheral T ...
- C#性能优化篇 - 基于索引器封装EPList
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Sy ...
- ngrx/store effects 使用总结2:列表展示
第一个计数器案例:http://www.cnblogs.com/axel10/p/8589122.html 完成了计数器案例后,现在开始比较能够完整的展示angular2+开发流程的案例:在线获取用户 ...
- 关联分析(Apriori算法)
两个概念: 频繁项集:常出现的物品集合 关联分析:找到诸如:尿布-->啤酒的关联,反过来则是另一条 两个控制参数: 项集的支持度(support):一个项集出现的次数在所有样本中出现的比例 可信 ...
- TopCoder SRM 301 Div2 Problem 1000 CorrectingParenthesization(区间DP)
题意 给定一个长度为偶数的字符串.这个字符串由三种括号组成. 现在要把这个字符串修改为一个符合括号完全匹配的字符串,改变一个括号的代价为$1$,求最小总代价. 区间DP.令$dp[i][j]$为把子 ...
- 余秋雨的话(与OI无关)
余秋雨的话 1.假如你想要一件东西,就放它走.它若能回来找你,就永远属于你:它若不回来,那根本就不是你的. 2. 一个人会落泪,是因为痛:一个人之所以痛,是因为在乎:一个人之所以在乎,是因为有感觉:一 ...
- Ubuntu 16.04下IntelliJ IDEA菜单显示乱码的问题解决
说明:这个问题一般是Ubuntu安装时默认使用了中文,而IDEA默认是以系统默认字体为主,所以就会出现乱码:要解决这种问题,就是在IDEA启动时强制设置为英文. 解决方式: 在idea.vmoptio ...
- 解决php中redis client进行subscribe操作出现timeout的问题
出现该问题的原因是poll设置接收超时所致,这个超时默认设置60s 设置Redis::OPT_READ_TIMEOUT配置项: 解决方法如下: <?php $redis = new Redis( ...
- datasnap——动态注册服务类
datasnap——动态注册服务类 在DataSnap的应用程序时,我们首先需要注册的服务器类,以提供访问客户端应用程序的服务器方法.通常的做法是使用DSServerClass组件,但有些时候,我们要 ...