Spring很常用的@Conditional注解的使用场景和源码解析
你好,我是刘牌!
介绍
今天要分享的是Spring的注解@Conditional,@Conditional是一个条件注解,它的作用是判断Bean是否满足条件,如果满足条件,则将Bean注册进IOC中,如果不满足条件,则不进行注册,这个注解在SpringBoot中衍生出很多注解,比如@ConditionalOnProperty,@ConditionalOnBean,@ConditionalOnClass等等,在SpringBoot中,这些注解用得很多。
文件服务场景
下面我们演示一些@Conditional的使用,在软件开发中,文件系统是必须的,但是系统的特点不一样,有些用户希望将文件保存在自己的服务器上,有些用户则没这种要求,这时候,文件可以保存在云上,也可以保存在自建文件系统上,那么面对不同用户的需求,我们的软件也要能够适配不同的环境,只需要简单的配置即可。
假设我们在开发过程中,我们的文件全部托管在云服务厂商的OSS上,代码逻辑也没有预留扩展,那么当用户需要私有化部署,我们可能就需要更改文件存储这边的逻辑,这样的设计是不合理的。
我们想一想,文件存储的代码逻辑是不同的,各个文件系统的实现方式和使用API各不相同,但是它们有一个共性,那就是能够上传文件,下载文件的,所以我们就应该抽象出一个公共接口,下面有不同的实现,比如Minio的文件上传下载等逻辑就使用Minio API去实现,FastDFS就使用FastDFS,OSS就使用OSS,下面我们就编写对应的代码。
编码实现
以下通过编码实现不同文件系统的逻辑实现隔离,统一提供接口的方案,一般我们都会将配置信息写在配置文件中,在配置文件中,使用storageType代表文件存储类型。
文件上传接口
在StorageService接口中,只简单定义了两个方法init()和put(),init()就是做一些初始化操作,比如参数配置,连接等,put()就是上传文件接口。
/**
 * 功能说明: 文件上传接口
 * <p>
 * Original @Author: steakliu-刘牌, 2023-04-03  09:54
 * <p>
 */
public interface StorageService {
    /**
     * 初始化文件存储
     */
    void init();
    /**
     * 上传文件
     * @param file
     */
    void put(MultipartFile file);
}
具体文件系统实现
以下是Minio的具体实现,在类上面使用了@Conditional注解,value值为MinioStorageCondition。
@Component
@Conditional(value = MinioStorageCondition.class)
public class MinioStorageService implements StorageService {
    @Override
    public void init() {
        // 初始化操作
    }
    @Override
    public void put(MultipartFile file) {
    }
}
MinioStorageCondition条件判断
MinioStorageCondition的作用就是判断条件是否匹配,它实现Condition接口,要使用@Conditional,其判断类必须要实现Condition接口,然后自己实现matches方法逻辑,以下就是判断storageType是否为minio,如果为minio,那么就返回true,就代表要创建MinioStorageService这个bean,为false则不创建。
public class MinioStorageCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String storageType = context.getEnvironment().getProperty("storageType");
        return "minio".equals(storageType);
    }
}
源码解析
spring在扫描bean的时候,会判断对应的bean是否有@Conditional注解,如果有,则会进入value中的类,进去判断是否符合条件,如果符合,则返回true,就能够注册,实际上如果符合条件,那么就能将BeanDefinition注册进BeanFactory,如果不符合,自然不能注册进。
如下是源码的时序图

从上面的时序图中可以看出,整个过程涉及的类还是挺多的,不过这还不是完整流程,只是从扫描类开始,Spring会扫描工程路径下的类,这个路径可以通过@ComponentScan进行指定,如果是SpringBoot项目,则就为当前工程,然后筛选出需要注册的bean并注册到BeanFactory,对于标注有@Conditional注解的类,会进入@Conditional中value的类中,就是上面的MinioStorageCondition或者FastDFSStorageCondition,然后进行匹配,不满足条件的则不会被注册。
@Conditional的具体流程也比较简单,就不一一赘述,可以看着上面的时序图去看源码实现。
总结
上面对@Conditional的使用,原理等进行简单的介绍,@Conditional注解在SpringBoot中用得还是比较多的,特别是它衍生出来的一些注解,这些注解都是基于它来进行二次封装的,在SpringBoot中,对于很多starter,里面几乎都会有@Conditional和@Conditional衍生注解的使用,我们后续会挑选出一些来说。
今天的分享就到这里,感谢你的观看,我们下期见!
Spring很常用的@Conditional注解的使用场景和源码解析的更多相关文章
- J2EE进阶(十三)Spring MVC常用的那些注解
		Spring MVC常用的那些注解 前言 Spring从2.5版本开始在编程中引入注解,用户可以使用@RequestMapping, @RequestParam,@ModelAttribute等等这样 ... 
- Spring源码解析02:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析
		一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ... 
- Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析
		一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ... 
- 【Spring实战】Spring注解配置工作原理源码解析
		一.背景知识 在[Spring实战]Spring容器初始化完成后执行初始化数据方法一文中说要分析其实现原理,于是就从源码中寻找答案,看源码容易跑偏,因此应当有个主线,或者带着问题.目标去看,这样才能最 ... 
- 【转】【Spring实战】Spring注解配置工作原理源码解析
		一.背景知识 在[Spring实战]Spring容器初始化完成后执行初始化数据方法一文中说要分析其实现原理,于是就从源码中寻找答案,看源码容易跑偏,因此应当有个主线,或者带着问题.目标去看,这样才能最 ... 
- Spring的JDK动态代理如何实现的(源码解析)
		前言 上一篇文章中提到了SpringAOP是如何决断使用哪种动态代理方式的,本文接上文讲解SpringAOP的JDK动态代理是如何实现的.SpringAOP的实现其实也是使用了Proxy和Invoca ... 
- 常用限流算法与Guava RateLimiter源码解析
		在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ... 
- Spring Boot  @Enable*注解源码解析及自定义@Enable*
		Spring Boot 一个重要的特点就是自动配置,约定大于配置,几乎所有组件使用其本身约定好的默认配置就可以使用,大大减轻配置的麻烦.其实现自动配置一个方式就是使用@Enable*注解,见其名知 ... 
- 一文了解@Conditional注解说明和使用
		 @Conditional:Spring4.0 介绍了一个新的注解@Conditional,它的逻辑语义可以作为"If-then-else-"来对bean的注册起作用. @Con ... 
- 一口气说出 6种,@Transactional注解的失效场景
		整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一口气说出 9种 分布式ID生成方式,面试官有点懵了 面试总被问 ... 
随机推荐
- 使用idea从零编写SpringCloud项目-Feign
			ps:Fegin和Ribbon 其实是差不多的东西,Fegin里面也是集成了Ribbon,不过咱们写代码不是要优雅嘛,使用Feign就会优雅很多了,看着比直接使用Ribbon舒坦一点 就不重新构建项目 ... 
- mybatis插入批量数据
			1 for循环重复调用dao,消耗大 2 sql语句编写插入多条,只用于少数 3 mybatis的batch插入 @Test public void testInsertBatch2() ... 
- C语言II—作业03
			1.作业头 这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/SE2020-3 这个作业要求在哪里 https://edu.cnblogs.com/cam ... 
- pandas数据增删改查+拼接
			pandas数据的拼接+增删改查 def lengthways_joint(df,df1): #纵向拼接 if list(df.columns) == list(df1.columns): leb_j ... 
- (五).JavaScript的数组
			1. 数组 1.1 数组的基础 数组:同种或不同数据类型数据的有序集合 功能:同时存储多个数据 数据:常量 变量 表达式 数组 函数 对象 定义方式:字面量定义或者构造函数定义 字面量定义数组(本质上 ... 
- win 11 VMware workstations b不可恢复的错误(vcpu-2)
			首先检查一下电脑有没有开启CPU虚拟化,我的已经开启了,按照百度的方法去控制面板卸载程序里面,找到VMware 右击更改 弹出的安装程序点修复,,结果修复出错了,显示写入文件D:\vm\glib-2. ... 
- 如何加快打开网页的速度------通过调节“QoS数据包计划程序”的“限制可保留宽带”实现&如何解决win10可能找不到gpedit.msc的问题
			参考:http://www.windowszj.com/news/win10/42119.html http://www.docin.com/p-1510367352.html(QoS数据包计划程序有 ... 
- pytest用例管理框架实战(基础篇)
			先安装pip install pytest pytest用例管理框架 默认规则: 1.py文件必须以test_开头或者_test结尾 2.类名必须以test开头 3.测试用例必须以test_开头 ge ... 
- LoadRunner——安装教程以及创建与录制(一)
			theme: channing-cyan 1. loadrunner12|loadrunner12官方版下载(附安装教程)+网盘下载+汉化包 CSDN下载及安装教程: https://blog.csd ... 
- RPA的市场需求
			最基本的RPA软件机器人定义:机器人通过记录员工在电脑桌面上的操作行为,将业务处理规则和操作行为记录下来,并模拟人的方式在电脑上自动执行一系列特定的工作流程.采用RPA软件机器人解决方案,快速实施,快 ... 
