【Spring Boot 源码学习】@Conditional 条件注解
Spring Boot 源码学习系列

@Conditional 条件注解
- 引言
- 往期内容
- 主要内容
- 1. 初识 @Conditional
- 2. @Conditional 的衍生注解
- 总结
引言
前面的博文,Huazie 带大家从 Spring Boot 源码深入了解了自动配置类的读取和筛选的过程,然后又详解了OnClassCondition、 OnBeanCondition、OnWebApplicationCondition 这三个自动配置过滤匹配子类实现。
在上述的博文中,我们其实已经初步涉及到了像 @ConditionalOnClass、@ConditionalOnBean、@ConditionalOnWebApplication 这样的条件注解,并且这些条件注解里面,我们都能看到 @Conditional 注解。

往期内容
在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:
| Spring Boot 源码学习 |
| Spring Boot 项目介绍 |
| Spring Boot 核心运行原理介绍 |
| 【Spring Boot 源码学习】@EnableAutoConfiguration 注解 |
| 【Spring Boot 源码学习】@SpringBootApplication 注解 |
| 【Spring Boot 源码学习】走近 AutoConfigurationImportSelector |
| 【Spring Boot 源码学习】自动装配流程源码解析(上) |
| 【Spring Boot 源码学习】自动装配流程源码解析(下) |
| 【Spring Boot 源码学习】深入 FilteringSpringBootCondition |
| 【Spring Boot 源码学习】OnClassCondition 详解 |
| 【Spring Boot 源码学习】OnBeanCondition 详解 |
| 【Spring Boot 源码学习】OnWebApplicationCondition 详解 |
主要内容
本篇我们重点介绍 @Conditional 条件注解,参见如下:
1. 初识 @Conditional
我们先来看看 @Conditional 注解的源码【Spring Context 5.3.25】:
/*** 表示组件仅在所有指定条件匹配时才有资格注册。* * 条件是在bean定义即将注册之前可以通过编程确定的任何状态(有关详细信息,请参阅Condition)。* * @Conditional注解可以以以下任意方式使用:* 作为类型级别的注释直接或间接地应用于带有@Component的任何类,包括@Configuration类* 作为元注释,用于组合自定义注释标签* 作为@Bean方法上的注释级别注解* * 如果一个@Configuration类被标记为@Conditional,则该类的所有@Bean方法、@Import注解和@ComponentScan注解都将受到条件约束。** @author Phillip Webb* @author Sam Brannen* @since 4.0* @see Condition*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {/*** 必须匹配才能注册组件的所有条件类*/Class<? extends Condition>[] value();}
翻看上述源码,可以看到 @Conditional 条件注解是从 Spring 4.0 开始引入的,它表示组件仅在所有指定条件匹配时才有资格注册。比如,当类加载器下存在某个指定的类的时候才会对注解的类进行实例化操作。
它唯一的元素属性是接口 Condition 的数组,只有数组中指定的所有 Condition 的 matches 方法都返回 true 的情况下,被注解的类才会被加载。我们前面讲到的 OnClassCondition 等类就是 Condition 的子类之一。
/*** 一个必须匹配才能注册的单个 Condition。** <p> 在 bean 定义即将被注册之前立即进行检查,并可以根据在该点可以确定的任何标准自由否决注册。** <p> 条件必须遵循与 BeanFactoryPostProcessor 相同的限制,并确保不要与 bean 实例进行交互。* 对于与 @Configuration beans交互的更细粒度的控制,请考虑实现 ConfigurationCondition 接口。** @author Phillip Webb* @since 4.0* @see ConfigurationCondition* @see Conditional* @see ConditionContext*/
@FunctionalInterface
public interface Condition {/*** 确定条件是否匹配。* @param context 条件上下文* @param metadata 正在检查的 AnnotationMetadata 或 MethodMetadata 的元数据* @return 如果条件匹配并且可以注册组件,则返回 true;否则返回 false,否决带有注解的组件的注册。*/boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);}
上述就是 Condition 接口的源码,它的 matches 方法用来确定条件是否匹配,其中两个参数分别如下:
-
ConditionContext:条件上下文,可通过该接口提供的方法来获得 Spring 应用的上下文信息,接口定义如下:public interface ConditionContext {/*** 返回一个 BeanDefinitionRegistry 对象,该对象将包含如果条件匹配时应该持有的bean定义。* 如果没有可用的注册表(这种情况很少见:只有当使用 ClassPathScanningCandidateComponentProvider 时才会出现),* 则会抛出IllegalStateException异常。*/BeanDefinitionRegistry getRegistry();/*** 返回一个 ConfigurableListableBeanFactory 对象,该对象将包含如果条件匹配时应该持有的bean定义,* 或者 如果bean工厂不可用(或者无法向下转型为 ConfigurableListableBeanFactory),则返回null。*/@NullableConfigurableListableBeanFactory getBeanFactory();/*** 返回当前应用程序正在运行的环境。*/Environment getEnvironment();/*** 返回当前正在使用的资源加载器。*/ResourceLoader getResourceLoader();/*** 返回应该用来加载额外类的 ClassLoader。如果系统类加载器不可访问,则返回null。*/@NullableClassLoader getClassLoader();} -
AnnotatedTypeMetadata:该接口提供了访问特定类或方法的注解功能,并且不需要加载类,可以用来检查带有@Bean注解的方法上是否还有其他注解。下面我们来查看下它的源码【spring-core 5.3.25】:
public interface AnnotatedTypeMetadata {// 返回一个MergedAnnotations对象,表示该类型的注解集合。MergedAnnotations getAnnotations();// 检查是否存在指定名称的注解,如果存在则返回true,否则返回false。default boolean isAnnotated(String annotationName) {return this.getAnnotations().isPresent(annotationName);}// 下面的方法,都是用来获取指定名称注解的属性值@Nullabledefault Map<String, Object> getAnnotationAttributes(String annotationName) {return this.getAnnotationAttributes(annotationName, false);}@Nullabledefault Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {MergedAnnotation<Annotation> annotation = this.getAnnotations().get(annotationName, (Predicate)null, MergedAnnotationSelectors.firstDirectlyDeclared());return !annotation.isPresent() ? null : annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));}@Nullabledefault MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {return this.getAllAnnotationAttributes(annotationName, false);}@Nullabledefault MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {Adapt[] adaptations = Adapt.values(classValuesAsString, true);return (MultiValueMap)this.getAnnotations().stream(annotationName).filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)).map(MergedAnnotation::withNonMergedAttributes).collect(MergedAnnotationCollectors.toMultiValueMap((map) -> {return map.isEmpty() ? null : map;}, adaptations));} }
2. @Conditional 的衍生注解
在 Spring Boot 的 autoconfigure 项目中提供了各类基于@Conditional 注解的衍生注解,它们均位于 spring-boot-autoconfigure 项目的 org.springframework.boot.autoconfigure.condition 包下,如下图所示:。

上述有好几个条件注解,我们已经接触过了,下面我们再仔细介绍一下:
-
@ConditionalOnBean:当容器中有指定 Bean 的条件下。 -
@ConditionalOnClass:当 classpath 类路径下有指定类的条件下。 -
@ConditionalOnCloudPlatform:当指定的云平台处于 active 状态时。 -
@ConditionalOnExpression:基于 SpEL 表达式的条件判断。 -
@ConditionalOnJava:基于 JVM 版本作为判断条件。 -
@ConditionalOnJndi:在 JNDI 存在的条件下查找指定的位置。 -
@ConditionalOnMissingBean:当容器里没有指定 Bean 的条件。 -
@ConditionalOnMissingClass:当类路径下没有指定类的条件下。 -
@ConditionalOnNotWebApplication:当项目不是一个 Web 项目的条件下。 -
@ConditionalOnProperty:当指定的属性有指定的值的条件下。 -
@ConditionalOnResource:类路径是否有指定的值。 -
@ConditionalOnSingleCandidate:当指定的 Bean 在容器中只有一个,或者有多个但是指定了首选的 Bean。 -
@ConditionalOnWarDeployment:当应用以 War 包形式部署时(例如在 Tomcat、Jetty 等 Web 服务器中) -
@ConditionalOnWebApplication:当项目是一个 Web 项目的条件下
如果我们仔细观察这些注解的源码,很快会发现它们其实都组合了@Conditional 注解,不同的是它们在注解中指定的条件(Condition)不同。
下面我们以前面博文中了解过的 @ConditionalOnWebApplication 为例,来对衍生条件注解进行一个简单的分析:
/*** 用于条件性地匹配应用程序是否为Web应用程序。默认情况下,任何Web应用程序都会匹配,但可以通过type()属性进行缩小范围。** @author Dave Syer* @author Stephane Nicoll* @since 1.0.0*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnWebApplication {// 所需的web应用类型Type type() default Type.ANY;// 可选应用类型枚举enum Type { // 任何类型ANY,// 基于servlet的web应用SERVLET,// 基于reactive的web应用REACTIVE}
}
通过查看 @ConditionalOnWebApplication 注解的源码,我们发现它的确组合了 @Conditional 注解,并且指定了对应的 Condition 为OnWebApplicationCondition。该类继承自 SpringBootCondition 并实现 AutoConfigurationImportFilter 接口。
有关 OnWebApplicationCondition 类的详细介绍,请查看笔者的《【Spring Boot 源码学习】OnWebApplicationCondition 详解》,
了解了条件类的相关内容后,我们可以用如下图来表示 Condition 接口相关功能及实现类:

总结
本篇我们介绍 @Conditional 条件注解及其衍生注解,至此有关自动配置装配的流程已经基本介绍完毕。
虽然我们从源码角度对自动装配流程有了清晰的认识,但还是不能熟练地运用。那么下篇博文,我们将以 Spring Boot 内置的 http 编码功能为例来分析一下整个自动配置的过程。
相关文章:
【Spring Boot 源码学习】@Conditional 条件注解
Spring Boot 源码学习系列 Conditional 条件注解 引言往期内容主要内容1. 初识 Conditional2. Conditional 的衍生注解 总结 引言 前面的博文,Huazie 带大家从 Spring Boot 源码深入了解了自动配置类的读取和筛选的过程,然后又详解了OnClassCondition、…...
jupyter_快速开始
文章目录 使用 Anaconda 启动 jupyter-lab纯 python 环境使用 jupyter-notebook纯 python 环境使用 jupyter-labjupyter-lab 配置文件相关jupyter-notebook 配置文件相关jupyter-lab 与 jupyter-notebook 的关系与区别 使用 Anaconda 启动 jupyter-lab 启动一个cmd 命令行&…...
英特尔 SGX 技术概述
目录 介绍概述指示结构Memory安全区页面缓存Enclave Page Cache (EPC)安全区页面缓存映射Enclave Page Cache Map (EPCM) Memory ManagementStructures页面信息Page Information (PAGEINFO)安全信息Security Information (SECINFO)分页加密元数据Paging …...
SpringBoot核心功能与基础配置
SpringBoot简介 原先的Spring程序缺点,包括依赖设置繁琐,每项jar的引用都需要自己撰写。并且配置繁琐,配置文件中也需要自己写加载bean等。由此针对原始的Spring程序,Pivotal团队提供的全新框架——SpringBoot,其设计…...
vue3后台管理框架之Mock开发
前言 在前后端对接中,有时后端的接口数据没有 那么快能给出,因此我们可以通过mock模拟自己的请求数据,在后端接口没有给出的同时,先使用mock请求的数据完成前端相关的逻辑 官方文档:vite-plugin-mock vite 的数据模…...
03_51单片机点亮LED灯
51单片机是一种非常常见的单片机型号,广泛应用于各种嵌入式系统和电子设备中。LED灯是一种常见的输出设备,用于显示信息或指示状态。下面是关于51单片机控制LED灯的介绍: 1. 连接LED灯:将LED的正极连接到51单片机的一个I/O引脚&a…...
【前端设计模式】之备忘录模式
备忘录模式是一种行为设计模式,它允许在不破坏封装性的前提下捕获和恢复对象的内部状态。在前端开发中,备忘录模式可以用于保存和恢复用户界面的状态,以及实现撤销和重做功能。 备忘录模式特性: 封装了对象的状态:备…...
复习Day15:栈与队列part02:20. 有效的括号、1047.删除字符串中所有相邻重复项
我用的方法是在leetcode再过一遍例题,明显会的就复制粘贴,之前没写出来就重写,然后从拓展题目中找题目来写。辅以Labuladong的文章看。然后刷题不用CLion了,使用leetcode自带的IDE模拟面试环境。 历史博客链接: http…...
基于Java的宠物商城管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...
Python的GIL存在的情况下,是否还有必要添加线程锁。
GIL锁的产生: 为了保证在单线程情况下,Python的正常执行和效率,GIL锁产生了,由于只有一把锁就不会产生死锁也不用切换。 对于Python语言而言,只有CPython解释器(用C语言编写的Python解释库)存在…...
基于下垂控制的孤岛双机并联逆变器环流抑制MATLAB仿真模型
微❤关注“电气仔推送”获得资料(专享优惠) 在实际应用中逆变器都是并联运行的,但是逆变器的并联运行也存在不少问题,由于线路阻抗差异、各个逆变器输出端瞬时电压幅值不同等,都容易导致环流的出现。环流会导致逆变器损耗增加,从而影响微电网的输出效率…...
spring事务面试题
1.Spring 事务实现方式有哪些? 事务就是一系列的操作原子操作,Spring事务机制主要 包括声明式事务和编程式事务。 编程式事务:通过编程的方式管理事务,自己设置未提交模式,自己获取连接,自己预编译,自己回…...
C++标准库算法整理
目录 1、数值操作 1.1、std::accumulate 1.2、std::inner_product 1.3、std::partial_sum 1.4、std::exclusive_scan 1.5、std::inclusive_scan 1.6、std::reduce 2、相邻元素 2.1、std::adjacent_difference 2.2、std::adjacent_find 2.3、std::unique 2.4、std::u…...
【Codeforces】Codeforces Round 903 (Div. 3)【待补】
Dashboard - Codeforces Round 903 (Div. 3) - Codeforces Problem - C - Codeforces Problem - D - Codeforces...
workerman 运行时报错 Call to undefined function posix_getpid()
使用 验证php扩展是否齐全 curl -Ss https://www.workerman.net/check | php缺少posix 下载 在 Linux 系统上,可以使用包管理器来安装 php-posix 扩展,例如 Ubuntu 系统可以通过以下命令进行安装: sudo apt-get install php-posix如果你使用…...
【探讨C++中的临时对象:一时之物还是永恒之道?】
在C编程中,临时对象是一个经常引起讨论的话题。它们是什么,为什么它们存在,以及如何正确使用它们?本文将深入探讨C中的临时对象,帮助您理解它们的含义和用途。 什么是临时对象? 临时对象(Temp…...
二叉树相关算法
1、二叉树基本操作 二叉树的定义就不在这里多说了,下面这个图就是一个简单的二叉树: 二叉树的三种遍历方式: 前序遍历:头左右,也就是先头后左再右:1245367 public static void prePrint(BinaryTreeNode …...
Vue_Bug npm install报错 code:128
Bug描述: npm install报错 code:128 npm ERR! Warning: Permanently added ‘github.com’ (ED25519) to the list of known hosts. npm ERR! gitgithub.com: Permission denied (publickey). npm ERR! fatal: Could not read from remote repository. n…...
【Unity ShaderGraph】| 如何快速制作一个 马赛克效果 实战
前言 【Unity ShaderGraph】| 如何快速制作一个 马赛克效果 实战一、效果展示二、马赛克效果四、应用实例 前言 本文将使用Unity 的ShaderGraph制作一个马赛克的效果,可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章:【Unity S…...
【Java 进阶篇】JavaScript DOM Document对象详解
在前端开发中,DOM(文档对象模型)扮演着重要的角色。它允许我们使用JavaScript来与网页文档进行交互,实现动态的网页效果。DOM的核心部分之一就是Document对象,它代表了整个HTML文档。在本篇博客中,我们将深…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
EasyRTC音视频实时通话功能在WebRTC与智能硬件整合中的应用与优势
一、WebRTC与智能硬件整合趋势 随着物联网和实时通信需求的爆发式增长,WebRTC作为开源实时通信技术,为浏览器与移动应用提供免插件的音视频通信能力,在智能硬件领域的融合应用已成必然趋势。智能硬件不再局限于单一功能,对实时…...
Linux中INADDR_ANY详解
在Linux网络编程中,INADDR_ANY 是一个特殊的IPv4地址常量(定义在 <netinet/in.h> 头文件中),用于表示绑定到所有可用网络接口的地址。它是服务器程序中的常见用法,允许套接字监听所有本地IP地址上的连接请求。 关…...
