Spring框架中的@Conditional系列注解
目录
- 1 @Contidional 介绍
- 1.1 Condition 接口
- 1.2 Spring @Conditional注解实例
- 1.3 @Conditional 与@Profile 的对比
- 2 Spring boot 扩展
- 2.1 @ConditionalOnClass和@ConditionalOnMissingClass注解
- 2.2 @ConditionalOnBean 和@ConditionalOnMissingBean注解
- 2.3 @ConditionalOnProperty注解
1 @Contidional 介绍

Conditional 是由SpringFramework提供的一个注解,位于 org.springframework.context.annotation 包内,定义如下。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional {Class<? extends Condition>[] value();}
SpringBoot 模块大量的使用@Conditional 注释,我们可以将Spring的@Conditional注解用于以下场景:
- 可以作为类级别的注解直接或者间接的与@Component相关联,包括@Configuration类;
- 可以作为元注解,用于自动编写构造性注解;
- 作为方法级别的注解,作用在任何@Bean方法上。
1.1 Condition 接口
我们需要一个类实现Spring提供的Condition接口,它会匹配@Conditional所符合的方法,然后我们可以使用我们在@Conditional注解中定义的类来检查。
public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
1.2 Spring @Conditional注解实例
作用在方法上
先来看一个简单一些的示例,我们假设有三个角色老师Teacher、学生Student和父母Parent,三种环境Linux、Windows和MacOSX,如果是Linux环境,就注册Teacher,如果是Windows环境就注册Parent,如果是Mac 环境就注册Student。代码示例如下:
- 首先创建Teacher和Student对象,没有任何的属性和方法,只是一个空类
//如果当前工程运行在Windows系统下,就注册Student
public class Student {}//如果当前工程运行在Linux系统下,就注册Teacher
public class Teacher {}// 如果是Mac OSX 系统,就注册Parent
public class Parent {}
- 创建一个LinuxCondition和一个WindowsCondition,LinuxCondition能够匹配Linux环境,WindowsCondition能够匹配Windows环境,MacOSX 系统匹配mac环境。
public class LinuxCondition implements Condition {public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 获取系统环境的属性String systemName = context.getEnvironment().getProperty("os.name");if(systemName.contains("Linux")){return true;}return false;}
}//自定义一个判断条件
public class WindowsCondition implements Condition {/** ConditionContext context: spring容器上下文环境* AnnotatedTypeMetadata metadata :@Conditional修饰类型信息*/public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {String systemName = context.getEnvironment().getProperty("os.name");if(systemName.contains("Windows")){return true;}return false;}}public class OsxCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {String property = context.getEnvironment().getProperty("os.name");if(property.equals("Mac OS X")){return true;}return false;}
}
- 下面来新建匹配注册环境,如果系统是Linux环境,就注册Teacher,如果系统是Windows,就注册Parent,如果是Mac 系统,就注册Student
@Configuration
public class AppConfig {@Conditional(OsxCondition.class)@Beanpublic Student student(){return new Student();}@Conditional(LinuxCondition.class)@Beanpublic Teacher teacher(){return new Teacher();}@Conditional(WindowsCondition.class)@Beanpublic Parent parent(){return new Parent();}
}
- 新建测试类进行测试
public class ConditionTest {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);String[] names = context.getBeanDefinitionNames();for(String name : names){System.out.println("name = " + name);}}
}
由输出可以看出,name = student 被输出到控制台,也就是说,我当前所用的系统环境是MacOSX环境,所以注册的是OSXCondition,也就是student的bean。
手动设置系统环境
也可以进行手动修改vm.options,把当前的系统环境变为Linux 或者Windows,以Idea为例:
在Edit Configurations中找到vm.options 选项,把系统环境改为 Linux,如下:
然后重新启动测试,发现Teacher 被注入进来了,修改当前环境为Windows,观察Parent也被注入进来并输出了。
作用在类上
@Conditional 注解可以作用在类上,表示此类下面所有的bean满足条件后都可以进行注入,通常与@Configuration注解一起使用。
- 新建一个
AppClassConfig,在类上标注@Conditional()注解,并配置相关bean,如下:
@Conditional(value = OsxCondition.class)
上文表示如果是OsxCondition.class 的话,就注册student、teacher、parent
- 测试类不用修改,直接用原测试类进行测试,发现student、 teacher、 parent 都被注册进来了
多个条件类
因为@Conditional注解的value 方法默认传递一个数组,所以可以接受多个condition,为了测试如下情况,
新建一个 TestCondition类,如下:
// 单纯为了测试
public class TestCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 返回false,表示不匹配return false;}
}
修改一下AppClassConfig
@Conditional(value = {OsxCondition.class,TestCondition.class})
也就是给@Conditional 多加了一个参数 TestCondition.class
启动之前的测试类,发现上述的bean都没有注入,也就是说,只有在满足OsxCondition.class 和 TestCondition.class 都为true的情况下,才会注入对应的bean,修改TestCondition.class的matches方法的返回值为true,重新观察返回结果,发现上述bean都被注入了。
1.3 @Conditional 与@Profile 的对比
@Spring3.0 也有一些和@Conditional 相似的注解,它们是Spring SPEL 表达式和Spring Profiles 注解 Spring4.0的@Conditional 注解要比@Profile 注解更加高级。@Profile 注解用来加载应用程序的环境。@Profile注解仅限于根据预定义属性编写条件检查。 @Conditional注释则没有此限制。
Spring中的@Profile 和 @Conditional 注解用来检查"If…then…else"的语义。然而,Spring4 @Conditional是@Profile 注解的更通用法。
- Spring 3中的 @Profiles仅用于编写基于Environment变量的条件检查。 配置文件可用于基于环境加载应用程序配置。
- Spring 4 @Conditional注解允许开发人员为条件检查定义用户定义的策略。 @Conditional可用于条件bean注册。
2 Spring boot 扩展
SpringBoot的spring-boot-autoconfigure模块也提供了Conditional系列的相关注解,这些注解能帮助开发者根据一定的条件去装载需要的Bean。

2.1 @ConditionalOnClass和@ConditionalOnMissingClass注解
当Spring加载的Bean被@ConditionOnClass注解标记时,类加载器会先去先找到指定的Class, 如果没有找到目标Class,那么被ConditionOnClass注解标记的类不会被Spring装载,相反ConditionalOnMissingBean是指如果没有找到目标Class, 那么就装载该类。
2.2 @ConditionalOnBean 和@ConditionalOnMissingBean注解
当Spring加载的Bean被@ConditionalOnBean注解标记时,接下来会先找到指定的Bean,如果没有找到目标Bean,那么被@ConditionalOnBean标记的类不会被Spring装载,相反ConditionalOnMissingBean是指如果没有Class, 那么就装载该Bean。
看一个例子, Dubbo与Springboot做自动装配时,先寻找BASE_PACKAGES_BEAN_NAME这个Bean, 如果Bean 不存在,那么serviceAnnotationBeanProcessor这个Bean不会被Spring 装载.
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@EnableDubboConfig
public class DubboAutoConfiguration {/*** Creates {@link ServiceAnnotationPostProcessor} Bean* dubbo.scan.base-packages* @param packagesToScan the packages to scan* @return {@link ServiceAnnotationPostProcessor}*/@ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)// 先找BASE_PACKAGES_BEAN_NAME 这个bean, 如果没有这个bean, 那么serviceAnnotationBeanProcessor不会被Spring装载。@ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)@Beanpublic ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)Set<String> packagesToScan) {return new ServiceAnnotationPostProcessor(packagesToScan);}}
使用@ConditionalOnMissingBean注解定义BASE_PACKAGES_BEAN_NAME这个Bean
/*** Dubbo Relaxed Binding Auto-{@link Configuration} for Spring Boot 2.0** @see DubboRelaxedBindingAutoConfiguration* @since 2.7.0*/
@Configuration
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
@AutoConfigureBefore(DubboRelaxedBindingAutoConfiguration.class)
public class DubboRelaxedBinding2AutoConfiguration {public PropertyResolver dubboScanBasePackagesPropertyResolver(ConfigurableEnvironment environment) {ConfigurableEnvironment propertyResolver = new AbstractEnvironment() {@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {Map<String, Object> dubboScanProperties = getSubProperties(environment.getPropertySources(), DUBBO_SCAN_PREFIX);propertySources.addLast(new MapPropertySource("dubboScanProperties", dubboScanProperties));}};ConfigurationPropertySources.attach(propertyResolver);return propertyResolver;}/*** The bean is used to scan the packages of Dubbo Service classes* 如果没有就创建* @param environment {@link Environment} instance* @return non-null {@link Set}* @since 2.7.8*/@ConditionalOnMissingBean(name = BASE_PACKAGES_BEAN_NAME)@Bean(name = BASE_PACKAGES_BEAN_NAME)public Set<String> dubboBasePackages(ConfigurableEnvironment environment) {PropertyResolver propertyResolver = dubboScanBasePackagesPropertyResolver(environment);return propertyResolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());}@ConditionalOnMissingBean(name = RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME, value = ConfigurationBeanBinder.class)@Bean(RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME)@Scope(scopeName = SCOPE_PROTOTYPE)public ConfigurationBeanBinder relaxedDubboConfigBinder() {return new BinderDubboConfigBinder();}}
2.3 @ConditionalOnProperty注解
该注解的作用是解析application.yml/application.properties 里的配置生成条件来生效,也是与@Configuration注解一起使用。
| 属性 | 功能 | 其他 |
|---|---|---|
| prefix | 读取配置里的前缀值为prefix的属性, 如果没有返回false | |
| name | 读取属性配置里的Key值,如果配置了prefix,那么需要先拼接prefix然后匹配havingValue值 | |
| havingValue | 匹配属性里的值 | |
| matchIfMissing | 当未找到对应的配置时是否匹配,默认为false, 如果为true,没有找到配置,那么也匹配。 |
使用场景,例如在指定数据源时,指定datasource的type。例如包含如下配置使用Hikari数据源。
spring.datasource.type=com.zaxxer.hikari.HikariDataSource

在使用时,一般设置matchIfMissing=false, 这样条件没有匹配上的话会Spring在扫描bean时会自动跳过该配置类。
也可以设定matchIfMissing=true,这种场景例如缓存,我们可以这样配置默认是开启缓存的。
@ConditionalOnProperty(name={cache.effect},marchIfMissing=true)public class CacheAutoConfiguration{// ...}
如果在application.properties里配置cache.effect=false, 那么该配置类就会跳过,这样配置就能使缓存不生效。
相关文章:
Spring框架中的@Conditional系列注解
目录 1 Contidional 介绍1.1 Condition 接口1.2 Spring Conditional注解实例1.3 Conditional 与Profile 的对比 2 Spring boot 扩展2.1 ConditionalOnClass和ConditionalOnMissingClass注解2.2 ConditionalOnBean 和ConditionalOnMissingBean注解2.3 ConditionalOnProperty注解…...
spring boot + minio 8.5.4 遇到 okhttp3包冲突
解决方案: 在你spring boot项目的根pom上指定okhttp3版本, <properties><okhttp3.version>4.8.1 </okhttp3.version></properties> 这样其他的模块引入minio就不会报错了 <dependencies><!--minio oss服务--><dependenc…...
springboot整合actuator、admin对应用程序进行监控
Spring Boot Actuator 是 Spring Boot 的一个子项目,可以对 Spring Boot 应用程序进行监控和管理,并对外提供了大量的端点,可以选择使用 HTTP 端点或 JMX 来管理和监控应用程序。 这篇文章主要介绍我们的应用程序中怎么加入actuator来对应用进…...
文举论金:黄金原油全面走势分析策略指导。
市场没有绝对,涨跌没有定势,所以,对市场行情的涨跌平衡判断就是你的制胜法宝。欲望!有句意大利谚语:让金钱成为我们忠心耿耿的仆人,否则,它就会成为一个专横跋扈的主人。空头,多头都…...
Fedora CoreOS 安装部署详解
《OpenShift 4.x HOL教程汇总》 Fedora CoreOS 的裸机安装方法_fedora coreos 安装-CSDN博客 OpenShift 4 - Fedora CoreOS (1) - 最简安装_fedora core 安装_dawnsky.liu的博客-CSDN博客 OpenShift 和 CoreOS 我们知道 Red Hat Enterprise Linux CoreOS(简称RHCOS&…...
Web应用开发 - 实训三 B Servlet基础
Web应用开发 - 实训三 B Servlet基础 前言: 零、前期准备准备工具创建项目导入 jar 包配置运行设置 一、实训第一部分第一张图第二张图第三张图 二、实训第二部分第一张图第二张图 前言: eclipse 是不可能用的,并不是说它界面丑,…...
Debian12安装 Docker
Docker中基本概念 镜像(Image) 镜像,从认识上简单的来说,就是面向对象中的类,相当于一个模板。从本质上来说,镜像相当于一个文件系统。Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配…...
Elasticsearch:为具有许多 and/or 高频术语的 top-k 查询带来加速
作者:Adrien Grand Disjunctive queries(term_1 OR term_2 OR ... OR term_n)非常常用,因此在提高查询评估效率方面它们受到了广泛关注。 Apache Lucene 对于评估 disjunctive queries 有两个主要优化:一方面用于详尽评…...
【pythonflask-1】简单实现加减乘除输入界面
app.py import flask from flask import Flask, render_template, request # 计算精确的浮点结果,float加法也计算不出来 from decimal import Decimalapp Flask(__name__)app.route(/) def home():return render_template(index.html)app.route(/calculate, meth…...
基于协同过滤算法的旅游推荐系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...
遇见问题:使用mybaties向数据库中插入数据,idea显示插入成功,但是数据库中并没有数据变化?
遇见问题:使用mybaties向数据库中插入数据,idea显示插入成功,但是数据库中并没有数据变化? 可能的原因有几种: 没有提交事务:在使用 MyBatis 进行数据库操作时,需要手动提交事务。你可以在插入数据完成后…...
markdown学习笔记
markdown学习笔记 1.文字(依靠HTML) 1.1文字缩进-空格转义符 单字符空:  半字符空: 1.2文字对齐 「居中:」<center> 居中 </center> or <p align"center"> 居中 …...
C++项目实战——基于多设计模式下的同步异步日志系统-⑧-日志落地类设计
文章目录 专栏导读抽象基类StdoutSink类设计FileSink类设计RollBySizeSink类设计日志落地工厂类设计日志落地类整理日志落地拓展测试RollByTimeSink类设计测试代码测试完整代码 专栏导读 🌸作者简介:花想云 ,在读本科生一枚,C/C领…...
从零开始探索C语言(八)----指针
文章目录 1. 什么是指针?2. 如何使用指针?3. NULL 指针4. 指针的算术运算5. 指针数组6. 指向指针的指针7. 传递指针给函数8. 从函数返回指针 有人说,指针是C语言的灵魂,所以学习C语言,学习指针是很有必要的。 通过指针…...
SpringMVC 的三种异常处理方式详解
目录 1. 什么是异常 2. 为什么要全局异常处理 3. SpringMVC异常分类 4. 异常处理思路 5. 三种异常处理方式示例 ① 配置 SimpleMappingExceptionResolver 处理器 ② 实现 HandlerExceptionResolver 接口 ③ 使用ControllerAdviceExceptionHandler实现全局异常 6. 响应…...
莫比乌斯召回系统介绍
当前召回系统只能召回相关性高的广告,但不能保证该广告变现能力强。莫比乌斯做了如下两点创新: 在召回阶段,引入CPM等业务指标作为召回依据在召回阶段,引入CTR模型,从而召回更多相关性高且变现能力强的广告 参考 百度…...
使用ASM修改组件化 ARouter
工程目录图 1. apt生成的字节码文件 2. asm 生成的代码 请点击下面工程名称,跳转到代码的仓库页面,将工程 下载下来 Demo Code 里有详细的注释 代码:TestCompont...
第21章_瑞萨MCU零基础入门系列教程之事件链接控制器ELC
本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总: ht…...
(二十八)大数据实战——Flume数据采集之kafka数据生产与消费集成案例
前言 本节内容我们主要介绍一下flume数据采集和kafka消息中间键的整合。通过flume监听nc端口的数据,将数据发送到kafka消息的first主题中,然后在通过flume消费kafka中的主题消息,将消费到的消息打印到控制台上。集成使用flume作为kafka的生产…...
vue3:22、vue-router的使用
import { createRouter, createWebHistory } from vue-router//history模式:createWebHistory //hash模式:createWebHashHistory//vite中的环境变量 import.meta.env.BASE_URL 就是vite.config.js中的base配置项 const router createRouter({history:…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
