Spring中@Conditional注解详解:条件装配的终极指南

一、为什么要用条件装配?

在实际开发中,我们经常需要根据不同的运行环境配置参数依赖情况动态决定是否注册某个Bean。例如:

  • 开发环境使用内存数据库,生产环境连接真实数据库

  • 当存在某个类时才启用特定功能

  • 根据配置文件开关决定是否初始化组件

这时就需要用到Spring的条件装配机制,而@Conditional注解正是实现这一功能的核心!

二、@Conditional注解简介

1. 核心作用

@Conditional是Spring 4.0引入的条件化Bean注册注解,通过它可以实现:

if(满足指定条件) {注册当前Bean
}

2. 核心接口

其底层依赖Condition接口:

public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

3. 常见派生注解

Spring Boot基于它扩展了:

  • @ConditionalOnProperty

  • @ConditionalOnClass

  • @ConditionalOnMissingBean

  • 等20+条件注解

三、使用方式(三步走)

步骤1:自定义条件类

public class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 返回true则创建Beanreturn checkSomeCondition(); }
}

步骤2:标注条件注解

@Configuration
public class AppConfig {@Bean@Conditional(MyCondition.class) // 关键注解public MyService myService() {return new MyService();}
}

步骤3:验证结果

MyCondition.matches()返回true时,MyService会被注册到容器,否则忽略。

四、实战案例:多环境配置

场景描述

根据不同的运行环境(dev/test/prod)加载不同的数据源配置。

1. 定义环境条件
public class EnvCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 获取环境变量String env = context.getEnvironment().getProperty("app.env", "dev");// 获取注解中定义的目标环境Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnEnv.class.getName());String targetEnv = (String) attrs.get("value");return targetEnv.equalsIgnoreCase(env);}
}// 自定义条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(EnvCondition.class)
public @interface ConditionalOnEnv {String value();
}
2. 配置不同环境Bean
@Configuration
public class DataSourceConfig {// 开发环境数据源@Bean@ConditionalOnEnv("dev")public DataSource devDataSource() {return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();}// 生产环境数据源@Bean@ConditionalOnEnv("prod")public DataSource prodDataSource() {HikariDataSource ds = new HikariDataSource();ds.setJdbcUrl("jdbc:mysql://prod-server:3306/db");// 其他配置...return ds;}
}
3. 测试验证
// 设置环境变量
System.setProperty("app.env", "prod");ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// 生产数据源将被注入
DataSource dataSource = ctx.getBean(DataSource.class); 

五、高级用法:组合条件

多个条件可以通过AllNestedConditions实现逻辑与

public class AllConditions extends AllNestedConditions {public AllConditions() {super(ConfigurationPhase.REGISTER_BEAN);}@ConditionalOnClass(DataSource.class)static class OnClassCondition {}@ConditionalOnProperty("spring.datasource.url")static class OnPropertyCondition {}
}// 使用组合条件
@Configuration
@Conditional(AllConditions.class)
public class DataSourceAutoConfiguration {// 当类路径存在DataSource且配置了url时生效
}

六、注意事项

  1. 条件判断时机:发生在Bean定义阶段,早于Bean实例化

  2. 优先级问题@Conditional的优先级高于@Profile

  3. 避免循环依赖:条件判断中不要直接获取Bean实例

  4. 调试技巧:通过-Ddebug查看条件评估报告(Spring Boot)

七、总结

@Conditional为Spring应用提供了灵活的条件装配能力,通过本文你可以:

✅ 掌握自定义条件装配的实现方法
✅ 了解多环境配置的最佳实践
✅ 学会处理复杂条件组合场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12447.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis代金卷(优惠卷)秒杀案例-多应用版

Redis代金卷(优惠卷)秒杀案例-单应用版-CSDN博客 上面这种方案,在多应用时候会出现问题,原因是你通过用户ID加锁 但是在多应用情况下,会出现两个应用的用户都有机会进去 让多个JVM使用同一把锁 这样就需要使用分布式锁 每个JVM都会有一个锁监视器,多个JVM就会有多个锁监视器…

ros 发布Topic

1、确定话题名称和消息类型 自定义话题名称&#xff0c;消息类型根据发送消息需要从std_msgs中查找确定 2、在main函数中通过NodeHander发布话题 // 创建一个NodeHandle对象&#xff0c;用于与ROS系统进行交互ros::NodeHandle nh;// 创建一个Publisher对象&#xff0c;用于发…

86.(2)攻防世界 WEB PHP2

之前做过&#xff0c;回顾一遍&#xff0c;详解见下面这篇博客 29.攻防世界PHP2-CSDN博客 既然是代码审计题目&#xff0c;打开后又不显示代码&#xff0c;肯定在文件里 <?php // 首先检查通过 GET 请求传递的名为 "id" 的参数值是否严格等于字符串 "admi…

毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统

目录 前言 课题背景和意义 实现技术思路 一、算法理论基础 1.1 卷积神经网络 1.2 目标检测算法 1.3 注意力机制 二、 数据集 2.1 数据采集 2.2 数据标注 三、实验及结果分析 3.1 实验环境搭建 3.2 模型训练 3.2 结果分析 最后 前言 &#x1f4c5;大四是整个大学…

AI取代人类?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

刷题记录 动态规划-7: 63. 不同路径 II

题目&#xff1a;63. 不同路径 II 难度&#xff1a;中等 给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角&#xff08;即 grid[0][0]&#xff09;。机器人尝试移动到 右下角&#xff08;即 grid[m - 1][n - 1]&#xff09;。机器人每次只能向下或者向右移动一步。…

深度求索DeepSeek横空出世

真正的强者从来不是无所不能&#xff0c;而是尽我所能。多少有关输赢胜负的缠斗&#xff0c;都是直面本心的搏击。所有令人骄傲振奋的突破和成就&#xff0c;看似云淡风轻寥寥数语&#xff0c;背后都是数不尽的焚膏继晷、汗流浃背。每一次何去何从的困惑&#xff0c;都可能通向…

51c视觉~CV~合集10

我自己的原文哦~ https://blog.51cto.com/whaosoft/13241694 一、CV创建自定义图像滤镜 热图滤镜 这组滤镜提供了各种不同的艺术和风格化光学图像捕捉方法。例如&#xff0c;热滤镜会将图像转换为“热图”&#xff0c;而卡通滤镜则提供生动的图像&#xff0c;这些图像看起来…

【论文复现】粘菌算法在最优经济排放调度中的发展与应用

目录 1.摘要2.黏菌算法SMA原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 本文提出了一种改进粘菌算法&#xff08;ISMA&#xff09;&#xff0c;并将其应用于考虑阀点效应的单目标和双目标经济与排放调度&#xff08;EED&#xff09;问题。为提升传统粘菌算法&#xf…

C++基础(2)

目录 1. 引用 1.1 引用的概念和定义 1.2 引用的特性 1.3 引用的使用 2. 常引用 3. 指针和引用的关系 4. 内联函数inline 5. nullptr 1. 引用 1.1 引用的概念和定义 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.29 NumPy+Scikit-learn(sklearn):机器学习基石揭秘

2.29 NumPyScikit-learn&#xff1a;机器学习基石揭秘 目录 #mermaid-svg-46l4lBcsNWrqVkRd {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-46l4lBcsNWrqVkRd .error-icon{fill:#552222;}#mermaid-svg-46l4lBcsNWr…

圆上取点(例题)

Protecting The Earth &#xff08;圆内取点&#xff09; 题目描述&#xff1a; 给定 K (地球上的人数)&#xff0c;你必须制作一个保护罩来保护他们。(地球上的人数&#xff09;&#xff0c;你必须制作一个保护罩来保护他们。 已知一个人只能站在整数的坐标上&#xff0c…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.19 线性代数核武器:BLAS/LAPACK深度集成

2.19 线性代数核武器&#xff1a;BLAS/LAPACK深度集成 目录 #mermaid-svg-yVixkwXWUEZuu02L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yVixkwXWUEZuu02L .error-icon{fill:#552222;}#mermaid-svg-yVixkwXWUEZ…

[leetcode·回溯算法]回溯算法解题套路框架

本文参考labuladong算法笔记[回溯算法解题套路框架 | labuladong 的算法笔记] 本文解决几个问题&#xff1a; 回溯算法是什么&#xff1f;解决回溯算法相关的问题有什么技巧&#xff1f;如何学习回溯算法&#xff1f;回溯算法代码是否有规律可循&#xff1f; 其实回溯算法和我…

SQL Server中RANK()函数:处理并列排名与自然跳号

RANK()是SQL Server的窗口函数&#xff0c;为结果集中的行生成排名。当出现相同值时&#xff0c;后续排名会跳过被占用的名次&#xff0c;形成自然间隔。与DENSE_RANK()的关键区别在于是否允许排名值连续。 语法&#xff1a; RANK() OVER ([PARTITION BY 分组列]ORDER BY 排序…

多线程的常用方法

getName和setName方法 注意点 setName方法最好放在线程启动之前 最好在线程启动之前修改名字&#xff0c;因为线程启动之后&#xff0c;如果执行过快的话&#xff0c;那么在调用 setName() 之前线程可能就已经结束了 MyThread t1 new MyThread("haha"); t1.setNa…

Unity游戏(Assault空对地打击)开发(6) 鼠标光标的隐藏

前言 鼠标光标在游戏界面太碍眼了&#xff0c;要隐藏掉。 详细操作 新建一个脚本HideCursor&#xff0c;用于隐藏光标。 写入以下代码。 意义&#xff1a;游戏开始自动隐藏光标&#xff0c;按Esc&#xff08;显示<-->隐藏&#xff09;。 using System.Collections; using…

【Linux系统】信号:再谈OS与内核区、信号捕捉、重入函数与 volatile

再谈操作系统与内核区 1、浅谈虚拟机和操作系统映射于地址空间的作用 我们调用任何函数&#xff08;无论是库函数还是系统调用&#xff09;&#xff0c;都是在各自进程的地址空间中执行的。无论操作系统如何切换进程&#xff0c;它都能确保访问同一个操作系统实例。换句话说&am…

冰蝎v4.0.5 来啦

webshell始终是渗透测试的热门&#xff0c;上次护网写冰蝎检测规则&#xff0c;加密流量&#xff0c;有点压力&#xff0c;今天终于有空来复现一下&#xff0c;我知道玩知乎的大佬很多&#xff0c;轻一点喷&#xff0c;学习新知识不丢人&#xff5e; ailx10 1949 次咨询 4.9 …

WPS怎么使用latex公式?

1、下载并安装mathtype https://blog.csdn.net/weixin_43135178/article/details/125143654?sharetypeblogdetail&sharerId125143654&sharereferPC&sharesourceweixin_43135178&spm1011.2480.3001.8118 2、将mathtype嵌入在WPS MathType面板嵌入器,免费工具…