这个需求应该也比较常见,在不同的条件下创建不同的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. DoTween可视化编程用法详解

    DoTween可视化编辑 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创新 ...

  2. linux中grep用法(“或”、“与”)

    1.普通用法 grep keyword 若果keyword中有空格 grep "keyword" 例如: ls | grep mp4 2.“与”操作(其实就是多次筛选) grep ...

  3. (4)格式化输出(%用法和format用法以及区别)

    %s用法(%s的用法是写多少个,后面就要传多少个) format用法(基本语法是通过{}和:来代替%.format函数可以接受不限个参数,位置可以不按顺序) 形式一(顺序填坑{}) >>& ...

  4. 计算n^k的开头三位和末尾三位(fmod(double x,double y)函数的引入)

    C 库函数 double fmod(double x, double y) 返回 x 除以 y 的余数. 所以fmod(x,1)得到的就是小数部分的值(如fmod(3.35,1)==0.35) htt ...

  5. 《DSP using MATLAB》Problem 4.12

    代码: function [As, Ac, r, v0] = invCCPP(b0, b1, a1, a2) % Determine the signal parameters Ac, As, r, ...

  6. jdreact相关操作注意事项

    1:sublime 安装 babel 插件可以 识别react代码,变色,使用javascipt(babel): 2:热更新:import React, {Component } from 'reac ...

  7. Uboot启动命令使用

    1.查看根文件系统中的内容 打断Uboot的启动,默认从SD卡启动,查看根文件系统中/boot下的内容(根文件系统在mmcblk0p1上):=> mmc rescan=> ext4ls m ...

  8. 应用解决告诉你什么时候该用ajax

    第一.请求的提交是为了页面数据的显示,这时候用户一般不希望看到页面的刷新,是使用AJAX的一个最佳时候. 第二.如果请求提交后,用户能从页面感觉到提交结果,这时候,也最好不要有页面刷新,推荐使用AJA ...

  9. TNS-12535 TNS-00505的处理方法

    原文地址:TNS-12535 TNS-00505的处理方法 作者:wzq609 硬件说明: 操作系统版本:ORACLE LINUX 6.3  64位 数据库版本:11.2.0.3   64位 问题说明 ...

  10. spring boot 项目文件结构

    启动类建议放在RootPackage的原因: 根据SpringBoot的内置实现,Spring默认从@ComponentScan注解所在的位置开始向后扫描,也就是说,只要我们将组件放在启动类所在的Ro ...