SpringBoot(15)—@Conditional注解

作用 @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件的才给容器注册Bean。

一、概述

1、@Conditional注解定义

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

2、Condition

我们点进去看后,发现它是一个接口,有一个方法。

@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

3、ConditionContext

它持有不少有用的对象,可以用来获取很多系统相关的信息,来丰富条件判断,接口定义如下

public interface ConditionContext {
/**
* 获取Bean定义
*/
BeanDefinitionRegistry getRegistry();
/**
* 获取Bean工程,因此就可以获取容器中的所有bean
*/
@Nullable
ConfigurableListableBeanFactory getBeanFactory();
/**
* environment 持有所有的配置信息
*/
Environment getEnvironment();
/**
* 资源信息
*/
ResourceLoader getResourceLoader();
/**
* 类加载信息
*/
@Nullable
ClassLoader getClassLoader();
}

二、案例

需求 根据当前系统环境的的不同实例不同的Bean,比如现在是Mac那就实例一个Bean,如果是Window系统实例另一个Bean。

1、SystemBean

首先创建一个Bean类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SystemBean {
/**
* 系统名称
*/
private String systemName;
/**
* 系统code
*/
private String systemCode;
}

2、通过Configuration配置实例化Bean

@Slf4j
@Configuration
public class ConditionalConfig {
/**
* 如果WindowsCondition的实现方法返回true,则注入这个bean
*/
@Bean("windows")
@Conditional({WindowsCondition.class})
public SystemBean systemWi() {
log.info("ConditionalConfig方法注入 windows实体");
return new SystemBean("windows系统","002");
}
/**
* 如果LinuxCondition的实现方法返回true,则注入这个bean
*/
@Bean("mac")
@Conditional({MacCondition.class})
public SystemBean systemMac() {
log.info("ConditionalConfig方法注入 mac实体");
return new SystemBean("Mac ios系统","001");
}
}

3、WindowsCondition和MacCondition

这两个类都实现了Condition接口, 只有matches方法返回true才会实例化当前Bean

1)WindowsCondition

@Slf4j
public class WindowsCondition implements Condition {
/**
* @param conditionContext:判断条件能使用的上下文环境
* @param annotatedTypeMetadata:注解所在位置的注释信息
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//获取当前环境信息
Environment environment = conditionContext.getEnvironment();
//获取bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//获得当前系统名
String property = environment.getProperty("os.name");
//包含Windows则说明是windows系统,返回true
if (property.contains("Windows")){
log.info("当前操作系统是:Windows");
return true;
}
return false;
}
}

2) MacCondition

@Slf4j
public class MacCondition implements Condition { @Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Mac")) {
log.info("当前操作系统是:Mac OS X");
return true;
}
return false;
}
}

4、测试类测试

/**
* @author xub
* @date 2019/6/13 下午10:42
*/
@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class TestConditionOn { @Autowired
private SystemBean windows;
@Autowired
private SystemBean mac; @Test
public void test() {
if (windows != null) {
System.out.println("windows = " + windows);
}
if (mac != null) {
System.out.println("linux = " + mac);
}
}
}

运行结果

通过运行结果可以看出

1、虽然配置两个Bean,但这里只实例化了一个Bean,因为我这边是Mac电脑,所以实例化的是mac的SystemBean

2、注意一点,我们可以看出 window并不为null,而是mac实例化的Bean。说明 只要实例化一个Bean的,不管你命名什么,都可以注入这个Bean。

修改一下

这里做一个修改,我们把ConditionalConfig中的这行代码注释掉。

// @Conditional({WindowsCondition.class})

再运行下代码

通过运行结果可以看出,配置类的两个Bean都已经注入成功了。

注意 当同一个对象被注入两次及以上的时候,那么你在使用当前对象的时候,名称一定要是两个bean名称的一个,否则报错。比如修改为

    @Autowired
private SystemBean windows;
@Autowired
private SystemBean mac;
@Autowired
private SystemBean linux;

在启动发现,报错了。

意思很明显,就是上面只实例化成功一个SystemBean的时候,你取任何名字,反正就是把当前已经实例化的对象注入给你就好了。

但是你现在同时注入了两个SystemBean,你这个时候有个名称为linux,它不知道应该注入那个Bean,所以采用了报错的策略。

GitHub源码 https://github.com/yudiandemingzi/spring-boot-study

项目名称 03-conditional

### 参考

1、Spring @Conditional注解

只要自己变优秀了,其他的事情才会跟着好起来(中将3)

SpringBoot(15)—@Conditional注解的更多相关文章

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

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

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

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

  3. SpringBoot自定义Condition注解

        最近碰到个这样的需求,需要同一套代码适配个版本数据库(数据库不同,且部分表的字段及关联关系可能会不同),即这套代码配置不同的数据库都能跑.项目采用的框架为SpringBoot+Mybatis. ...

  4. Spring中的@conditional注解

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

  5. Spring Conditional注解使用小结

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

  6. 一文了解@Conditional注解说明和使用

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

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

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

  8. springboot的@ConditionalOnClass注解

    大家好,我是"良工说技术". 今天给大家带来的是springboot中的@ConditionalOnClass注解的用法.上次的@ConditionalOnBean注解还记得吗? ...

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

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

随机推荐

  1. ajax配置项中的type与method

    1. jQuery中ajax配置项中的使用type与method的区别本质上两个配置项是没有区别的,区别在于两者出现的时间不同,type对于目前jQuery的版本全部兼容,也就是说$.ajax({ t ...

  2. <String> 161 358

    161. One Edit Distance 1. 两个字符串的长度之差大于1,直接返回False. 2. 两个字符串的长度之差等于1,长的那个字符串去掉一个字符,剩下的应该和短的字符串相同. 3. ...

  3. IT兄弟连 HTML5教程 HTML5表单 新增的表单属性1

    HTML5 Input表单为<form>和<input>标签添加了几个新属性,属性如表1. 1  autocomplete属性 autocomplete属性规定form或inp ...

  4. Maven使用之packaging类型

    项目的打包类型:pom.jar.war 项目中一般使用maven进行模块管理,每个模块下对应都有一个pom文件,pom文件中维护了各模块之间的依赖和继承关系.项目模块化可以将通用的部分抽离出来,方便重 ...

  5. C sharp #005# 对象与对象变量

    饮水思源:金老师的自学网站 索引 自动装箱 “只读”对象 设定启动窗体 ShowDialog与Show 自动装箱 基本类型的变量值可以自动装箱到一个object对象中, 反过来,object对象也可以 ...

  6. oracle相邻表记录交换(单双两两交换)

    在博客园的博问中看到了一个这样的提问:一个表中有id和name两个字段,id是连续非空不重复的,想要交换相邻表记录的name值(单双两两交换). 另外,如果最后的单独行没有对应的下一行匹配记录的话,就 ...

  7. sql server报【将截断字符串或二进制数据】错误

    会出现这个错误的原因是因为表设置的列长度小于要插入的数据的长度. 可以从下列的6个方面去排查: 1.表设置的列名长度太短. 2.插入的数据太长. 3.有默认值. 4.有触发器. 5 从char数据类型 ...

  8. Git - Git简介与客户端安装

    简介 Git是目前世界上最先进的分布式版本控制系统(没有之一)! 集中式版本控制系统(CVS/SVN),版本库是集中存放在中央服务器的,而一般工作的时候,用的都是自己的电脑,所以要先从中央服务器取得最 ...

  9. 深入selenium模块基础操作

    selenium模块的基本操作 一.模拟浏览器 ​ 谷歌.Firefox.Safari等浏览器 browser=webdriver.Chrome() browser=webdriver.Firefox ...

  10. Eclipse:批量将Java源代码文件的编码从GBK转为UTF-8

    很简单的几行代码,就可以批量将GBK格式的java文件转为UTF-8格式. 基本上所有文本文件的编码转换都可以采用这种方式. import java.io.File; import java.io.I ...