你好,我是刘牌!

介绍

今天要分享的是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注解的使用场景和源码解析的更多相关文章

  1. J2EE进阶(十三)Spring MVC常用的那些注解

    Spring MVC常用的那些注解 前言 Spring从2.5版本开始在编程中引入注解,用户可以使用@RequestMapping, @RequestParam,@ModelAttribute等等这样 ...

  2. Spring源码解析02:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  3. Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  4. 【Spring实战】Spring注解配置工作原理源码解析

    一.背景知识 在[Spring实战]Spring容器初始化完成后执行初始化数据方法一文中说要分析其实现原理,于是就从源码中寻找答案,看源码容易跑偏,因此应当有个主线,或者带着问题.目标去看,这样才能最 ...

  5. 【转】【Spring实战】Spring注解配置工作原理源码解析

    一.背景知识 在[Spring实战]Spring容器初始化完成后执行初始化数据方法一文中说要分析其实现原理,于是就从源码中寻找答案,看源码容易跑偏,因此应当有个主线,或者带着问题.目标去看,这样才能最 ...

  6. Spring的JDK动态代理如何实现的(源码解析)

    前言 上一篇文章中提到了SpringAOP是如何决断使用哪种动态代理方式的,本文接上文讲解SpringAOP的JDK动态代理是如何实现的.SpringAOP的实现其实也是使用了Proxy和Invoca ...

  7. 常用限流算法与Guava RateLimiter源码解析

    在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...

  8. Spring Boot @Enable*注解源码解析及自定义@Enable*

      Spring Boot 一个重要的特点就是自动配置,约定大于配置,几乎所有组件使用其本身约定好的默认配置就可以使用,大大减轻配置的麻烦.其实现自动配置一个方式就是使用@Enable*注解,见其名知 ...

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

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

  10. 一口气说出 6种,@Transactional注解的失效场景

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一口气说出 9种 分布式ID生成方式,面试官有点懵了 面试总被问 ...

随机推荐

  1. 实验一Linux系统与应用准备

    实验一Linux系统与应用准备 |这个作业属于哪个课程|内容| | ---- | ---- | ---- | |这个作业属于哪个课程|2021春季Linux系统与应用 (南昌航空大学 - 信息工程学院 ...

  2. greenDao基础用法(一)

    1.配置 1.1 在 build.gradle(project) 中,加入这句 classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // a ...

  3. Kicad使用技巧--原理图复用

    平时主要使用AD.kicad和立创eda,最近在琢磨一下各个软件的使用技巧,提升一下画图效率,首先想到的就是原理图复用,我想象中的原理图复用应该像AutoCAD的图块功能一样. 这次先说kicad,摸 ...

  4. windows消息机制_PostMessage和SendMessage

    1.子线程中建立一个窗口 为了在后面比较这两个函数,先使用win32 windows程序中建立子线程,在子线程中建立一个窗口. (1)新建一个 win32 windows应用程序 (2)定义子窗口的窗 ...

  5. linux软件安装篇

    nginx篇 第一件事情 cd /etc/yum.repo.d mv CentOS-Base.repo CentOS-Base.repo.bak wget -O CentOS-Base.repo ht ...

  6. MyBatis-Plus插入值后返回主键

    LZ做练手设计的时候有这样一个订单需求,先插入订单表数据(t_order),再写入订单详情表(t_orderDetail),详情表需要有一个与t_order的外键约束 t_order ( oid    ...

  7. lc.59 螺旋矩阵 II

    题目描述 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix . 示例 输入:n = 3 输出:[[1,2,3],[8,9, ...

  8. 解决ssh $host jps bash: jps: command not found 问题

    问题描述 使用 ssh $host jps 命令报错,连本机也会有这样的情况,但是分开使用并没有问题,即ssh $host下执行jps命令并不会报错. 原因 因为ssh远程连接到服务器的环境变量中不包 ...

  9. python random包常用函数

    random.random() random.random()方法返回一个随机数,其在0至1的范围之内,以下是其具体用法: import random print ("随机数: " ...

  10. (Winform程序带源码) 弹出输入框和获取输入框的值

    弹出输入框和获取输入框的值: private void button1_Click(object sender, EventArgs e) { string returnValue = Microso ...