Spring Boot 核心机制之 @Conditional:从原理到实战(一次讲透)

在使用 Spring Boot 的过程中,很多人会接触到:

  • @Conditional
  • @ConditionalOnProperty
  • @ConditionalOnClass

但往往只是"会用",却不知道它到底解决什么问题。

这篇文章帮你彻底搞清楚:

👉 @Conditional 到底是什么、什么时候触发、怎么用、适合用在哪

一、什么是 @Conditional(本质一句话)

👉 @Conditional = 条件装配机制

根据条件,决定某个 Bean 是否被加载到 Spring 容器中

二、先纠正一个常见误区(非常重要)

很多人第一反应是:

❌ 用来做环境切换(dev / test / prod)

👉 这是不准确的!

正确分工是:

功能 用什么
多环境切换 @Profile
条件装配 @Conditional

👉 举个对比:

环境切换(Profile)

java 复制代码
@Profile("dev")
@Bean
public ApiService mockApi() {}

条件控制(Conditional)

java 复制代码
@Bean
@ConditionalOnProperty(name = "feature.pay-enabled", havingValue = "true")
public PayService payService() {}

👉 总结一句:

Profile 控制"在哪个环境生效",Conditional 控制"这个功能有没有"

三、@Conditional 在启动流程中的位置(核心)

Spring 启动流程中:

java 复制代码
扫描类
    ↓
解析配置类
    ↓
⭐ 执行 @Conditional 判断
    ↓
注册 BeanDefinition
    ↓
创建 Bean

👉 关键点:

@Conditional 发生在"Bean 创建之前"

更准确一点:

扫描到类

检查 @Conditional

true → 注册 BeanDefinition

false → 直接跳过(相当于不存在)

四、核心原理(你必须理解)

@Conditional 本质是:

@Conditional(XXXCondition.class)

你要实现一个类:

java 复制代码
public class MyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true; // true 加载,false 不加载
    }
}

👉 这个 matches() 决定:

返回值 结果
true 加载 Bean
false 不加载

五、最常用的几个注解(你实际用这些)

Spring Boot 已经帮你封装好了:

1️⃣ @ConditionalOnProperty(最常用 ⭐)

java 复制代码
@Bean
@ConditionalOnProperty(name = "feature.pay-enabled", havingValue = "true")
public PayService payService() {}

yaml

java 复制代码
feature:
  pay-enabled: true

👉 作用:

配置开关控制功能是否开启

2️⃣ @ConditionalOnClass

@ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")

👉 用于自动配置(判断依赖是否存在)

3️⃣ @ConditionalOnMissingBean

@ConditionalOnMissingBean(PayService.class)

👉 如果没有 Bean 才创建(避免覆盖)

六、典型使用场景(企业真实用法)


✅ 1. 功能开关(最常见)

java 复制代码
feature:
sms-enabled: false
java 复制代码
@ConditionalOnProperty(name = "feature.sms-enabled", havingValue = "true")
@Bean
public SmsService smsService() {}

👉 效果:

  • false → 系统没有短信功能
  • true → 才有

✅ 2. 第三方接入控制

java 复制代码
pay:
wechat-enabled: true
java 复制代码
@ConditionalOnProperty(name = "pay.wechat-enabled", havingValue = "true")
@Bean
public WechatPayService wechatPayService() {}

✅ 3. 自动配置(Spring Boot 核心机制)

@AutoConfiguration

@ConditionalOnClass(DataSource.class)

👉 Spring Boot 就是这么"按需加载"的

七、一个非常关键的理解(必须记住)

👉 @Conditional 不是权限控制


❌ 错误理解

用户是 VIP → 用 @Conditional 控制 ❌


✅ 正确做法

第一层:系统能力(Conditional)

系统有没有 VIP 功能


第二层:用户权限(业务代码)

java 复制代码
if (user.isVip()) {
vipService.use();
}

👉 总结:

@Conditional 控制"系统有没有功能",不是"用户能不能用"

八、和 Android 的对比(帮助理解)

Android Spring
Flavor Profile
BuildConfig Environment
if 判断 @Conditional
不同 APK 不同 Bean

👉 本质差异:

类型 时机
Android Flavor 编译期
Spring Conditional 运行期(启动时)

九、实战推荐写法(你可以直接用)

feature:

pay-enabled: true

sms-enabled: false

vip-enabled: true

java 复制代码
@ConditionalOnProperty(name = "feature.pay-enabled", havingValue = "true")
@Bean
public PayService payService() {}

👉 搭配:

java 复制代码
@Autowired(required = false)
private PayService payService;

十、面试标准回答(直接背)

@Conditional 是 Spring 的条件装配机制,在容器启动时根据条件决定 Bean 是否注册。它通常用于功能开关、自动配置以及第三方组件加载。与 Profile 不同,Profile 主要用于环境切换,而 Conditional 更偏向于控制系统能力是否存在。


十一、总结(最重要)

@Conditional 的本质:

控制 Bean 是否存在

发生时机:

容器启动 → 注册 BeanDefinition 阶段

适用场景:

功能开关 / 自动配置 / 模块控制

不适用:

用户权限判断

核心理解

👉 @Conditional 不是控制"执行不执行"

👉 而是控制:

这个 Bean 在系统里"有没有"

下一篇:

AOP + 日志 + traceId 完整链路追踪(企业级模板)

内容包括:

  • 请求唯一 traceId
  • AOP 自动打印日志
  • 日志贯穿 Controller → Service → DB
  • 出问题一条链路查到底
相关推荐
Aision_1 小时前
从工具调用到 MCP、Skill完整学习记录
java·python·gpt·学习·langchain·prompt·agi
zc.z5 小时前
JAVA实现:纯PCM格式音频转换成BASE64
java·音视频·pcm
mask哥5 小时前
力扣算法java实现汇总整理(上)
java·算法·leetcode
无风听海5 小时前
深入剖析 YARP 的 Transforms:构建灵活的反向代理转换管道
后端·中间件·asp.net
Gopher_HBo6 小时前
负载均衡
后端
自由生长20246 小时前
RAG已死?什么标题党啊!
后端
Aaswk6 小时前
Java Lambda 表达式与流处理
java·开发语言·python
是宇写的啊7 小时前
Spring AOP
java·spring
万邦科技Lafite7 小时前
京东item_get接口实战案例:实时商品价格监控全流程解析
java·开发语言·数据库·python·开放api·淘宝开放平台
东方小月7 小时前
5分钟搞懂Harness Engineering(驾驭工程):从提示词到AI Agent的进化之路
前端·后端·架构