@Conditional:Spring4.0 介绍了一个新的注解@Conditional,它的逻辑语义可以作为"If…then…else…"来对bean的注册起作用。

@Contidional 介绍

​ Conditional 是由 SpringFramework 提供的一个注解,位于 org.springframework.context.annotation 包内,定义如下。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional { Class<? extends Condition>[] value(); }

​ SpringBoot 模块大量的使用@Conditional 注释,我们可以将Spring的@Conditional注解用于以下场景:

  • 可以作为类级别的注解直接或者间接的与@Component相关联,包括@Configuration类;
  • 可以作为元注解,用于自动编写构造性注解;
  • 作为方法级别的注解,作用在任何@Bean方法上。

Condition 接口

​ 我们需要一个类实现Spring提供的Condition接口,它会匹配@Conditional所符合的方法,然后我们可以使用我们在@Conditional注解中定义的类来检查。

public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Spring @Conditional注解实例

作用在方法上

​ 先来看一个简单一些的示例,我们假设有三个角色老师Teacher、学生Student和父母Parent,三种环境Linux、Windows和MacOSX,如果是Linux环境,就注册Teacher,如果是Windows环境就注册Parent,如果是Mac 环境就注册Student。代码示例如下:

  • 首先创建Teacher和Student对象,没有任何的属性和方法,只是一个空类
//如果当前工程运行在Windows系统下,就注册Student
public class Student {} //如果当前工程运行在Linux系统下,就注册Teacher
public class Teacher {} // 如果是Mac OSX 系统,就注册Parent
public class Parent {}
  • 创建一个LinuxCondition和一个WindowsCondition,LinuxCondition能够匹配Linux环境,WindowsCondition能够匹配Windows环境,MacOSX 系统匹配mac环境。

public class LinuxCondition implements Condition { public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取系统环境的属性
String systemName = context.getEnvironment().getProperty("os.name");
if(systemName.contains("Linux")){
return true;
}
return false;
}
} //自定义一个判断条件
public class WindowsCondition implements Condition { /*
* ConditionContext context: spring容器上下文环境
* AnnotatedTypeMetadata metadata :@Conditional修饰类型信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String systemName = context.getEnvironment().getProperty("os.name");
if(systemName.contains("Windows")){
return true;
}
return false;
} } public class OsxCondition implements Condition { @Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String property = context.getEnvironment().getProperty("os.name");
if(property.equals("Mac OS X")){
return true;
}
return false;
}
}
  • 下面来新建匹配注册环境,如果系统是Linux环境,就注册Teacher,如果系统是Windows,就注册Parent,如果是Mac 系统,就注册Student

@Configuration
public class AppConfig { @Conditional(OsxCondition.class)
@Bean
public Student student(){
return new Student();
} @Conditional(LinuxCondition.class)
@Bean
public Teacher teacher(){
return new Teacher();
} @Conditional(WindowsCondition.class)
@Bean
public Parent parent(){
return new Parent();
}
}
  • 新建测试类进行测试

public class ConditionTest { public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
String[] names = context.getBeanDefinitionNames();
for(String name : names){
System.out.println("name = " + name);
}
}
}

由输出可以看出,name = student 被输出到控制台,也就是说,我当前所用的系统环境是MacOSX环境,所以注册的是OSXCondition,也就是student的bean。

手动设置系统环境

也可以进行手动修改vm.options,把当前的系统环境变为Linux 或者Windows,以Idea为例:

Edit Configurations中找到vm.options 选项,把系统环境改为 Linux,如下:

然后重新启动测试,发现Teacher 被注入进来了,修改当前环境为Windows,观察Parent也被注入进来并输出了。

作用在类上

​ @Conditional 注解可以作用在类上,表示此类下面所有的bean满足条件后都可以进行注入,通常与@Configuration注解一起使用。

  • 新建一个AppClassConfig,在类上标注@Conditional()注解,并配置相关bean,如下:
@Conditional(value = OsxCondition.class)

上文表示如果是OsxCondition.class 的话,就注册student、teacher、parent

  • 测试类不用修改,直接用原测试类进行测试,发现student、 teacher、 parent 都被注册进来了

多个条件类

​ 因为@Conditional注解的value 方法默认传递一个数组,所以可以接受多个condition,为了测试如下情况,

新建一个 TestCondition类,如下:

// 单纯为了测试
public class TestCondition implements Condition { @Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 返回false,表示不匹配
return false;
}
}

修改一下AppClassConfig

@Conditional(value = {OsxCondition.class,TestCondition.class})

也就是给@Conditional 多加了一个参数 TestCondition.class

启动之前的测试类,发现上述的bean都没有注入,也就是说,只有在满足OsxCondition.class 和 TestCondition.class 都为true的情况下,才会注入对应的bean,修改TestCondition.class的matches方法的返回值为true,重新观察返回结果,发现上述bean都被注入了。

@Conditional 与@Profile 的对比

​ @Spring3.0 也有一些和@Conditional 相似的注解,它们是Spring SPEL 表达式和Spring Profiles 注解 Spring4.0的@Conditional 注解要比@Profile 注解更加高级。@Profile 注解用来加载应用程序的环境。@Profile注解仅限于根据预定义属性编写条件检查。 @Conditional注释则没有此限制。

​ Spring中的@Profile 和 @Conditional 注解用来检查"If…then…else"的语义。然而,Spring4 @Conditional是@Profile 注解的更通用法。

  • Spring 3中的 @Profiles仅用于编写基于Environment变量的条件检查。 配置文件可用于基于环境加载应用程序配置。
  • Spring 4 @Conditional注解允许开发人员为条件检查定义用户定义的策略。 @Conditional可用于条件bean注册。

文章参考:

https://blog.csdn.net/xcy1193068639/article/details/81491071

一文了解@Conditional注解说明和使用的更多相关文章

  1. spring 3.x变通实现@Conditional注解的功能

    在某些情况下,我们要根据当前的系统配置决定是否初始化一个bean,也就是条件性加载,比如本地缓存或者分布式缓存,亦或是采用http实现或者socket实现.在spring 4.x中,可以使用新增的@C ...

  2. Spring中的@conditional注解

    今天主要从以下几方面来介绍一下@Conditional注解 @Conditional注解是什么 @Conditional注解怎么使用 1,@Conditional注解是什么 @Conditional注 ...

  3. Spring Conditional注解使用小结

    今天我们来总结下Conditional注解的使用. Conditional注解 增加配置类Config package condition; import org.springframework.co ...

  4. springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用

    这个需求应该也比较常见,在不同的条件下创建不同的bean,具体场景很多,能看到这篇的肯定懂我的意思. 倘若不了解spring4.X新加入的@Conditional注解的话,要实现不同条件创建不同的be ...

  5. spring in action学习笔记七:@Conditional注解的用法

    @Profile注解是@Conditional注解的一个例子.即@Profile也是用@Conditional注解来实现的. 必须让条件实现Condition这个接口. 下面的案例讲如果环境中有mag ...

  6. Spring @Conditional注解 详细讲解及示例

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xcy1193068639/article/details/81491071 前言: @Conditi ...

  7. SpringBoot系列之@Conditional注解用法简介

    SpringBoot系列之@Conditional注解用法简介 引用Spring官方文档的说法介绍一下@Conditional注解:Spring5.0.15版本@Conditional注解官方文档 @ ...

  8. SpringBoot(15)—@Conditional注解

    SpringBoot(15)-@Conditional注解 作用 @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件的才给容器注册Bean. 一.概述 1 ...

  9. spring中@Conditional注解

    @Conditional是Spring4新提供的注解,它的作用是根据某个条件加载特定的bean. 我们需要创建实现类来实现Condition接口,这是Condition的源码 public inter ...

随机推荐

  1. 挑战程序设计竞赛》P345 观看计划

                                                 <挑战程序设计竞赛>P345 观看计划 题意:一周一共有M个单位的时间.一共有N部动画在每周si时 ...

  2. pat 甲级 1049. Counting Ones (30)

    1049. Counting Ones (30) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue The tas ...

  3. java中的BitSet

    (1)BitSet类     大小可动态改变, 取值为true或false的位集合.用于表示一组布尔标志. 此类实现了一个按需增长的位向量.位 set 的每个组件都有一个 boolean 值.用非负的 ...

  4. javascript 表格隔行换色

    用到的知识点: 获取表格元素 tbody 和 rows都是有索引的 这里我们只有一组tbody所以 索引是0 偶数行 索引取余2为0 奇数行 索引取余2不为0 通过 遍历行索引设置相应的颜色. < ...

  5. hdu 3072 有向图缩点成最小树形图计算最小权

    题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新 ...

  6. AC日记——第K大的数 51nod 1105

    1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * ...

  7. HDU1086 You can Solve a Geometry Problem too(计算几何)

    You can Solve a Geometry Problem too                                         Time Limit: 2000/1000 M ...

  8. Protobuf C#

    // ProtoBuf序列化            using(var file = System.IO.File.Create("Person.bin"))            ...

  9. 修改xampp默认sql密码

    1 登录localhost/phpmyadmin 点击权限修改 修改root@localhost下的密码并执行 2 刷新页面 找到xampp文件夹下的phpMyAdmin文件夹中的config.inc ...

  10. VS2010中 报错:error C2146、error C4430 原因一:缺少CvvImage类

    今天用vs2010打开vs2008的一个工程,报了好多错: 1>e:\visual studio 2010\projects\imageprojects\morphology\morpholog ...