Spring 中的 @Conditional 注解的作用是什么?
- 标签:后端、Spring
🏛 业务架构师
@Conditional 的作用是让 Bean 的注册带上条件:指定的 Condition 匹配才装配,否则跳过。Spring Boot 在它之上派生了一整套场景注解,构成自动配置的判断中枢:
@ConditionalOnClass:类路径有某类才生效(引了 Redis 依赖才装配 RedisTemplate);@ConditionalOnMissingBean:容器没有同类型 Bean 才装配——框架给默认值、业务可覆盖的机制;@ConditionalOnProperty:配置项满足条件才生效(开关式装配);- 还有 OnWebApplication、OnExpression、OnBean 等。
业务架构师视角,这个注解是**"按需供给、平滑扩展"的平台化基石**:
- 公司 starter 的标准姿势:我们封装统一日志/监控/多租户 starter 时,全部用条件装配——业务方引了依赖自动生效,想自定义就注册自己的 Bean 覆盖默认实现,平台与业务的扩展契约就靠 OnMissingBean 达成;
- 功能开关的装配级实现:
@ConditionalOnProperty让"灰度开关"控制的不只是运行时行为,连 Bean 是否存在都可控,省内存也省误触发; - 多环境适配:同一套代码在有无 MQ、有无注册中心的环境下都能启动,交付物一份、环境差异内部消化。
需要业务化判断时还能自定义 Condition(比如"仅当租户数大于 N 才启用分库路由")。一句话:@Conditional 把"装配决策"代码化,是组件平台化必须掌握的能力。
🏗 系统架构师
作用:按条件装配 Bean——条件类实现 Condition 接口,匹配才注册。@Profile 是它的特化;Spring Boot 自动配置整个建立在它的派生家族上:
@ConditionalOnClass:类路径存在某类才装配——starter 的核心:引依赖即生效;@ConditionalOnMissingBean:用户未自定义才给默认——用户配置永远优先的开放性;@ConditionalOnProperty(配置开关)、@OnWebApplication、@OnBean等。
架构价值(重点讲):
- 它把「装配期决策」从运行期 if/else 提前到启动时——启动即确定形态,无运行时分枝开销,也让 Native AOT 成为可能(AOT 要求构建期确定装配结果);
- 条件装配是公司平台 starter 的机制基础:平台把日志、追踪、安全按条件(依赖存在加配置开关)统一注入,业务方零配置合规——这是平台工程的标准手法;
- 条件要可观测:
--debug输出条件评估报告,是排查「Bean 为什么没装配」的第一现场。
💻 全栈开发专家
条件装配:满足条件才注册 Bean,是 Boot 自动配置的根基。
java
// 自定义条件:类路径有 XXL-JOB 且配置开关打开才启用
public class XxlJobEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta) {
return ctx.getClassLoader()
.getResource("com/xxl/job/core/XxlJobSpringExecutor.class") != null
&& ctx.getEnvironment().getProperty("xxl.job.enabled", Boolean.class, false);
}
}
@Configuration
@Conditional(XxlJobEnabledCondition.class)
public class XxlJobConfig { }Boot 在它之上派生了一整套场景注解,自动配置类里随处可见:
@ConditionalOnClass/@ConditionalOnMissingClass:类路径探测,避免硬依赖@ConditionalOnMissingBean:用户没自定义才提供默认——用户配置优先的核心机制@ConditionalOnProperty(havingValue/matchIfMissing)@ConditionalOnBean、@ConditionalOnWebApplication
写自定义 starter 就是这套组合拳。排查"自动配置为什么没生效",启动加 --debug 看 ConditionEvaluationReport:Negative match 一栏写清卡在哪个条件——比如 @ConditionalOnClass 找不到类,多半是依赖没引或版本不对,这招排查 jar 冲突极快。