这个需求应该也比较常见,在不同的条件下创建不同的bean,具体场景很多,能看到这篇的肯定懂我的意思。

倘若不了解spring4.X新加入的@Conditional注解的话,要实现不同条件创建不同的bean还是比较麻烦的,可能需要硬编码一些东西做if判断。那么现在有个@Conditional注解后,事情就简单多了。用法很简单,直接上代码。

新建一个springboot项目,添加一个Configuration标注的类,我们通过不同的条件表达式来创建bean。

  1.  
    package com.tianyalei.condition;
  2.  
     
  3.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
  4.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  5.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  6.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  7.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  8.  
    import org.springframework.context.annotation.Bean;
  9.  
    import org.springframework.context.annotation.Conditional;
  10.  
    import org.springframework.context.annotation.Configuration;
  11.  
     
  12.  
    /**
  13.  
    * Created by wuweifeng on 2017/10/11.
  14.  
    */
  15.  
    @Configuration
  16.  
    public class Config {
  17.  
     
  18.  
    @Conditional(MyCondition.class)
  19.  
    @Bean
  20.  
    public String condition() {
  21.  
    System.err.println("自定义的condition的match方法返回值为true时,才会进入该方法创建bean");
  22.  
    return "";
  23.  
    }
  24.  
     
  25.  
    /**
  26.  
    * 该Abc class位于类路径上时
  27.  
    */
  28.  
    @ConditionalOnClass(Abc.class)
  29.  
    @Bean
  30.  
    public String abc() {
  31.  
    System.err.println("ConditionalOnClass true");
  32.  
    return "";
  33.  
    }
  34.  
     
  35.  
    // @ConditionalOnClass(Abc.class)
  36.  
    // @Bean
  37.  
    // public Abc newAbc() {
  38.  
    // System.err.println("ConditionalOnClass true");
  39.  
    // return new Abc();
  40.  
    // }
  41.  
     
  42.  
    /**
  43.  
    * 存在Abc类的实例时
  44.  
    */
  45.  
    @ConditionalOnBean(Abc.class)
  46.  
    @Bean
  47.  
    public String bean() {
  48.  
    System.err.println("ConditionalOnBean is exist");
  49.  
    return "";
  50.  
    }
  51.  
     
  52.  
    @ConditionalOnMissingBean(Abc.class)
  53.  
    @Bean
  54.  
    public String missBean() {
  55.  
    System.err.println("ConditionalOnBean is missing");
  56.  
    return "";
  57.  
    }
  58.  
     
  59.  
    /**
  60.  
    * 表达式为true时
  61.  
    */
  62.  
    @ConditionalOnExpression(value = "true")
  63.  
    @Bean
  64.  
    public String expresssion() {
  65.  
    System.err.println("expresssion is true");
  66.  
    return "";
  67.  
    }
  68.  
     
  69.  
    /**
  70.  
    * 配置文件属性是否为true
  71.  
    */
  72.  
    @ConditionalOnProperty(
  73.  
    value = {"abc.property"},
  74.  
    matchIfMissing = false)
  75.  
    @Bean
  76.  
    public String property() {
  77.  
    System.err.println("property is true");
  78.  
    return "";
  79.  
    }
  80.  
    }

这里面有个空类Abc.class,你可以就创建个叫Abc的类,里面是空的就行。

  1.  
    import org.springframework.context.annotation.Condition;
  2.  
    import org.springframework.context.annotation.ConditionContext;
  3.  
    import org.springframework.core.type.AnnotatedTypeMetadata;
  4.  
     
  5.  
    /**
  6.  
    * Created by wuweifeng on 2017/10/11.
  7.  
    */
  8.  
    public class MyCondition implements Condition {
  9.  
    @Override
  10.  
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
  11.  
    //判断当前系统是Mac,Windows,Linux
  12.  
    return conditionContext.getEnvironment().getProperty("os.name").contains("Mac");
  13.  
    }
  14.  
    }

@Conditional(MyCondition.class)
这句代码可以标注在类上面,表示该类下面的所有@Bean都会启用配置
也可以标注在方法上面,只是对该方法启用配置

除了自己自定义Condition之外,Spring还提供了很多Condition给我们用
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)

以上是一些常用的注解,其实就是条件判断,如果为true了就创建Bean,为false就不创建,就这么简单。

这些注解里的条件可以是多个,也可以赋默认值,也可以标注在类上,如果标注在类上,则对类里的所有@Bean方法都生效。

其中@ConditionalOnProperty是指在application.yml里配置的属性是否为true,其他的几个都是对class的判断。

我在配置里加上abc.property = true这个配置就可以测试上面的代码了。

然后再来一个对类进行多个条件标注的例子:

  1.  
    package com.tianyalei.condition;
  2.  
     
  3.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  4.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  5.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  6.  
    import org.springframework.context.annotation.Bean;
  7.  
    import org.springframework.context.annotation.Configuration;
  8.  
     
  9.  
    /**
  10.  
    * Created by wuweifeng on 2017/10/11.
  11.  
    */
  12.  
    @Configuration
  13.  
    @ConditionalOnProperty(
  14.  
    value = {"abc.property"},
  15.  
    matchIfMissing = false
  16.  
    )
  17.  
    @ConditionalOnClass(Abc.class)
  18.  
    public class Multi {
  19.  
    @Bean
  20.  
    @ConditionalOnMissingBean({Abc.class})
  21.  
    public String check() {
  22.  
    System.err.println("multi check");
  23.  
    return "check";
  24.  
    }
  25.  
    }

OK,代码很简单,运行看看结果

可能上面的那些你用的地方不常见,那我来举一个我正在使用的例子。我的应用是基于SpringCloud的,在线上部署时有eureka来做注册中心,而在本地环境下,我的应用是单机的,不需要eureka,但是代码里已经引入了eureka了,每次启动就会自动去连接eureka,然后控制台就开始报错。虽然不影响功能,但是看着一直不停的报错也是不顺眼。

那么我就可以使用Condition注解来解决它。

  1.  
    /**
  2.  
    * @author wuweifeng wrote on 2017/11/25.
  3.  
    * 根据部署环境动态决定是否启用eureka
  4.  
    */
  5.  
    @Component
  6.  
    @ConditionalOnProperty(value = "open.eureka")
  7.  
    @EnableDiscoveryClient
  8.  
    public class JudgeEnableDiscoveryClient {
  9.  
    }

我把EnableDiscoveryClient这个注解单独放个类里,里面什么也不写,条件就是application.yml里配置的open.eureka
如果我只想让线上的环境开启eureka,那么我就在application-prod.yml里配上open.eureka=true,其他的yml什么也不写就行了。这样本地启动时就相当于没有开启EnableDiscoveryClient。

使用场景还是蛮多的,具体的看情况,但是需要记住有这么个注解,以便不时之需。

springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用的更多相关文章

  1. Spring之2:Spring Bean动态注册、删除

    IoC容器的初始化包括BeanDefinition的Resource定位.载入和注册这三个基本的过程. 一.Resource定位.BeanDefinition的资源定位有resourceLoader通 ...

  2. jquery利用appendTo动态创建元素

    动态创建元素可以说是DOM中常做的事情,下面我来介绍在jquery中利用appendTo来动态创建元素,有需要的朋友可参考参考. 当HTML字符串是没有属性的元素是, 内部使用document.cre ...

  3. Springboot定时任务原理及如何动态创建定时任务

    一.前言 上周工作遇到了一个需求,同步多个省份销号数据,解绑微信粉丝.分省定时将销号数据放到SFTP服务器上,我需要开发定时任务去解析文件.因为是多省份,服务器.文件名规则.数据规则都不一定,所以要做 ...

  4. Spring BPP中优雅的创建动态代理Bean

    一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出Cglib方式创建的代理Bean和ProxyFact ...

  5. Spring-Boot基于配置按条件装Bean

    背景 同一个接口有多种实现,项目启动时按某种规则来选择性的启用其中一种实现,再具体一点,比如Controller初始化的时候,根据配置文件的指定的实现类前缀,来记载具体Service,不同Servic ...

  6. springBoot 动态注入bean(bean的注入时机)

    springBoot 动态注入bean(bean的注入时机) 参考博客:https://blog.csdn.net/xcy1193068639/article/details/81517456

  7. SpringBoot动态注入Bean

    目的: 在程序运行期间,动态添加Bean进入到Spring容器. 目前使用到的场景: 对当当网的ElasticJob进行封装,通过自定义注解@ElasticJob的方式开启分布式定时任务. 当所有的B ...

  8. OAF 动态创建组件以及动态绑定属性

    在开发中,我们遇到以下一个需求. 一个表格左侧有5列是固定存在的,右侧有N列是动态生成的,并且该N列中第一列可输入,第二列是不可编辑的,但是是数字,如果小于0,那么就要显示为红色,重点标识出来. 首先 ...

  9. SpringBoot27 JDK动态代理详解、获取指定的类类型、动态注册Bean、接口调用框架

    1 JDK动态代理详解 静态代理.JDK动态代理.Cglib动态代理的简单实现方式和区别请参见我的另外一篇博文. 1.1 JDK代理的基本步骤 >通过实现InvocationHandler接口来 ...

随机推荐

  1. kafka集群安装,配置

    1.安装+配置(集群) 192.168.0.10.192.168.0.11.192.168.0.12(每台服务器kafka+zookeeper) # kafka依赖java环境,需要提前安装好jdk. ...

  2. U-Boot_bmp_logo_hacking

    /*********************************************************************** * U-Boot_bmp_logo_hacking * ...

  3. gcc -o test test.c编译报错

    报错内容 /tmp/cc7eQyD4.o: In function `main':test.c:(.text+0x51): undefined reference to `sqrt'collect2: ...

  4. js三级联动

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  5. javaScript 之set/get方法的使用

    例1:var fe={ name:'leony', $age:null, get age(){ if(this.$age == undefined){ //this.$age == undefined ...

  6. HTML标签 select 里 动态添加option

    HTML标签 select 里 动态添加option: ☆ var today = new Date(); var yearNow = today.getFullYear(); var optiong ...

  7. 自动AC机

    可以在lemon和cena环境下使用. #include<iostream> #include<cstdio> #include<cstring> #include ...

  8. MySQL--Alter Table注意事项

    ======================================================================== ALTER TABLE 和FLUSH TABLE导致的 ...

  9. log parser 微软iis 日志分析

    Log Parser 2.2 您可以从 Microsoft 下载中心下载 Log Parser. Log Parser 2.2 是一个功能强大的通用工具,它可对基于文本的数据(如日志文件.XML 文件 ...

  10. SQL 存储过程入门(五)

    好久没来博客园留下点东西,忙到找工作,最近把工作落实了. 最近公司的业务都是存储过程开发,发现去维护起来相当困难. 由于是维护项目,产品很久前都发布了,然而有一些修改,让我们去修改现在的逻辑,去看懂人 ...