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
  • 出问题一条链路查到底
相关推荐
米花米唐7 小时前
Spring AI 2.0 MCP服务器搭建与使用
后端
程序猿DD7 小时前
OctaFuse Gateway 2.9.0:用户限流控制、自定义转发头与管理后台升级
后端·api
三千星7 小时前
Java开发者转型AI工程化Week 5:让RAG学会思考、看见与自检
后端
一个Ai的杂货铺7 小时前
exit 0 也会撒谎:一个"绿灯盲跑"了一个月的定时任务,尸检报告
后端
hfywmsj7 小时前
广州餐饮铺位招租的选址架构:流量入口与成本函数分析
java·大数据·jvm·广州餐饮铺位招租
北漂EDA码路7 小时前
现代 C++20:move、forward 与完美转发,EDA 大型程序为什么离不开它
后端
爪哇岛国人7 小时前
原来我一直理解错了:实现接口真的必须实现所有方法吗?
java
泡海椒7 小时前
JQuick-Java快速入门教程:轻量级规则引擎环境搭建与首个脚本运行实战
后端
万年咸鱼8 小时前
Java BufferedOutputStream 详解:原理、用法与性能优化
java·开发语言·性能优化
万年咸鱼8 小时前
Java BufferedInputStream 详解:原理、用法与实战
java·开发语言·python