springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用
这个需求应该也比较常见,在不同的条件下创建不同的bean,具体场景很多,能看到这篇的肯定懂我的意思。
倘若不了解spring4.X新加入的@Conditional注解的话,要实现不同条件创建不同的bean还是比较麻烦的,可能需要硬编码一些东西做if判断。那么现在有个@Conditional注解后,事情就简单多了。用法很简单,直接上代码。
新建一个springboot项目,添加一个Configuration标注的类,我们通过不同的条件表达式来创建bean。
- package com.tianyalei.condition;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Conditional;
- import org.springframework.context.annotation.Configuration;
- /**
- * Created by wuweifeng on 2017/10/11.
- */
- @Configuration
- public class Config {
- @Conditional(MyCondition.class)
- @Bean
- public String condition() {
- System.err.println("自定义的condition的match方法返回值为true时,才会进入该方法创建bean");
- return "";
- }
- /**
- * 该Abc class位于类路径上时
- */
- @ConditionalOnClass(Abc.class)
- @Bean
- public String abc() {
- System.err.println("ConditionalOnClass true");
- return "";
- }
- // @ConditionalOnClass(Abc.class)
- // @Bean
- // public Abc newAbc() {
- // System.err.println("ConditionalOnClass true");
- // return new Abc();
- // }
- /**
- * 存在Abc类的实例时
- */
- @ConditionalOnBean(Abc.class)
- @Bean
- public String bean() {
- System.err.println("ConditionalOnBean is exist");
- return "";
- }
- @ConditionalOnMissingBean(Abc.class)
- @Bean
- public String missBean() {
- System.err.println("ConditionalOnBean is missing");
- return "";
- }
- /**
- * 表达式为true时
- */
- @ConditionalOnExpression(value = "true")
- @Bean
- public String expresssion() {
- System.err.println("expresssion is true");
- return "";
- }
- /**
- * 配置文件属性是否为true
- */
- @ConditionalOnProperty(
- value = {"abc.property"},
- matchIfMissing = false)
- @Bean
- public String property() {
- System.err.println("property is true");
- return "";
- }
- }
这里面有个空类Abc.class,你可以就创建个叫Abc的类,里面是空的就行。
- import org.springframework.context.annotation.Condition;
- import org.springframework.context.annotation.ConditionContext;
- import org.springframework.core.type.AnnotatedTypeMetadata;
- /**
- * Created by wuweifeng on 2017/10/11.
- */
- public class MyCondition implements Condition {
- @Override
- public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
- //判断当前系统是Mac,Windows,Linux
- return conditionContext.getEnvironment().getProperty("os.name").contains("Mac");
- }
- }
@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这个配置就可以测试上面的代码了。
然后再来一个对类进行多个条件标注的例子:
- package com.tianyalei.condition;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- /**
- * Created by wuweifeng on 2017/10/11.
- */
- @Configuration
- @ConditionalOnProperty(
- value = {"abc.property"},
- matchIfMissing = false
- )
- @ConditionalOnClass(Abc.class)
- public class Multi {
- @Bean
- @ConditionalOnMissingBean({Abc.class})
- public String check() {
- System.err.println("multi check");
- return "check";
- }
- }
OK,代码很简单,运行看看结果
可能上面的那些你用的地方不常见,那我来举一个我正在使用的例子。我的应用是基于SpringCloud的,在线上部署时有eureka来做注册中心,而在本地环境下,我的应用是单机的,不需要eureka,但是代码里已经引入了eureka了,每次启动就会自动去连接eureka,然后控制台就开始报错。虽然不影响功能,但是看着一直不停的报错也是不顺眼。
那么我就可以使用Condition注解来解决它。
- /**
- * @author wuweifeng wrote on 2017/11/25.
- * 根据部署环境动态决定是否启用eureka
- */
- @Component
- @ConditionalOnProperty(value = "open.eureka")
- @EnableDiscoveryClient
- public class JudgeEnableDiscoveryClient {
- }
我把EnableDiscoveryClient这个注解单独放个类里,里面什么也不写,条件就是application.yml里配置的open.eureka
如果我只想让线上的环境开启eureka,那么我就在application-prod.yml里配上open.eureka=true,其他的yml什么也不写就行了。这样本地启动时就相当于没有开启EnableDiscoveryClient。
使用场景还是蛮多的,具体的看情况,但是需要记住有这么个注解,以便不时之需。
springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用的更多相关文章
- Spring之2:Spring Bean动态注册、删除
IoC容器的初始化包括BeanDefinition的Resource定位.载入和注册这三个基本的过程. 一.Resource定位.BeanDefinition的资源定位有resourceLoader通 ...
- jquery利用appendTo动态创建元素
动态创建元素可以说是DOM中常做的事情,下面我来介绍在jquery中利用appendTo来动态创建元素,有需要的朋友可参考参考. 当HTML字符串是没有属性的元素是, 内部使用document.cre ...
- Springboot定时任务原理及如何动态创建定时任务
一.前言 上周工作遇到了一个需求,同步多个省份销号数据,解绑微信粉丝.分省定时将销号数据放到SFTP服务器上,我需要开发定时任务去解析文件.因为是多省份,服务器.文件名规则.数据规则都不一定,所以要做 ...
- Spring BPP中优雅的创建动态代理Bean
一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出Cglib方式创建的代理Bean和ProxyFact ...
- Spring-Boot基于配置按条件装Bean
背景 同一个接口有多种实现,项目启动时按某种规则来选择性的启用其中一种实现,再具体一点,比如Controller初始化的时候,根据配置文件的指定的实现类前缀,来记载具体Service,不同Servic ...
- springBoot 动态注入bean(bean的注入时机)
springBoot 动态注入bean(bean的注入时机) 参考博客:https://blog.csdn.net/xcy1193068639/article/details/81517456
- SpringBoot动态注入Bean
目的: 在程序运行期间,动态添加Bean进入到Spring容器. 目前使用到的场景: 对当当网的ElasticJob进行封装,通过自定义注解@ElasticJob的方式开启分布式定时任务. 当所有的B ...
- OAF 动态创建组件以及动态绑定属性
在开发中,我们遇到以下一个需求. 一个表格左侧有5列是固定存在的,右侧有N列是动态生成的,并且该N列中第一列可输入,第二列是不可编辑的,但是是数字,如果小于0,那么就要显示为红色,重点标识出来. 首先 ...
- SpringBoot27 JDK动态代理详解、获取指定的类类型、动态注册Bean、接口调用框架
1 JDK动态代理详解 静态代理.JDK动态代理.Cglib动态代理的简单实现方式和区别请参见我的另外一篇博文. 1.1 JDK代理的基本步骤 >通过实现InvocationHandler接口来 ...
随机推荐
- 6.2 socket 流协议与粘包
TCP IP协议是流协议,对上层协议来讲是没有边界的,主机A发送两个消息M1和M2,如下图所示: 主机A发送了M1和M2,主机B在接收时有4种情况: 1.先收了M1,又收了M2 2.M1.M2一起收到 ...
- php-fpm配置及操作
启动与停止 启动 /usr/local/php/sbin/php-fpm 停止 pkill php-fpm
- 多边形面积问题(hdoj2036)
杭电oj2036http://acm.hdu.edu.cn/showproblem.php?pid=2036 计算几何,求多边形的面积 只要记住这个公式: 如果逆时针给出点坐标,值为正, 如果顺时针给 ...
- 2018-2019-2 20165212 《网络对抗技术》Exp3 免杀原理与实践
2018-2019-2 20165212 <网络对抗技术>Exp3 免杀原理与实践 一.实验内容 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion ...
- Html页面Dom对象之Document
Document 对象 每个载入浏览器的 HTML 文档都会成为 Document 对象. Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问. 提示:Document 对 ...
- grandstack 基于graphql&&react&& apollo&& neo4j 的全栈开发工具
grandstack是一个基于graphql&&react&& apollo&& neo4j 的全栈开发工具. 有篇关于graphql 的5个常见问题的 ...
- JavaScript中类似PHP的uniqid()方法
JavaScript中类似PHP的uniqid()方法: function generateUIDNotMoreThan1million() { return ("0000" + ...
- shell脚本 如何调用Mysql的存储过程 解决方案
今天遇到一个在shell脚本里面要调用MySQL的存储过程,查阅了很多资料,发现有的都不好用,自己调试出了如下一种,拿来共享: 用mysql -e “ ”: 例如: mysql -uroot -p ...
- window下安装两个mysql服务
产生这个想法主要是因为win系统之前装了mysql,服务名为mysql.又重新安装xampp,导致mysql冲突,xampp中的mysql始终启动不起来. 解决方法如下: 1.修改xampp中my ...
- 【python】格式化字符
格式化字符串总结如下,红色部分是需要掌握部分: 以下几个常用的实例: 1.%s的使用 "%s is the author" %("paulwinflo")> ...