条件装配:@Conditional 与 @Profile

引言

同一套代码要在“开发/测试/生产”环境给出不同 Bean(如内存数据库 vs 正式库、假短信 vs 真短信)。条件装配让 Bean 的注册与否取决于运行环境或任意自定义条件:@Profile 做环境开关,@Conditional 做通用条件机制——@Profile 本身就是基于 @Conditional 实现的。

核心概念

  • @Profile("dev"):标注在 @Configuration/@Component/@Bean 方法上,仅当该 profile 激活时该 Bean 才注册。表达式支持 !dev(非)、dev | prod(或)、dev & cloud(与,以官方文档为准)。
  • 激活方式:启动参数 -Dspring.profiles.active=dev、环境变量 SPRING_PROFILES_ACTIVE,或编程 ctx.getEnvironment().setActiveProfiles("dev")(须在 refresh 之前)。
  • @Conditional(org.springframework.context.annotation):配合 Condition 接口使用;Condition.matches(ConditionContext, AnnotatedTypeMetadata) 返回 true 才注册。
  • 两者关系:@Profile 是元注解 @Conditional(ProfileCondition.class) 的组合注解。
  • 应用场景还包括 Boot 的 @ConditionalOnClass/@ConditionalOnProperty(那是 Boot 的扩展,机制同源)。

代码示例

public interface MessageSender { void send(String msg); }

// 开发环境:日志假实现
@Profile("dev")
@Component
public class LogSender implements MessageSender {
    public void send(String msg) { System.out.println("[dev-log] " + msg); }
}

// 生产环境:真短信实现
@Profile("prod")
@Component
public class RealSmsSender implements MessageSender {
    public void send(String msg) { /* 调用短信网关 */ }
}

// 自定义条件:JDK 版本 >= 17 才启用
public class Jdk17Condition implements Condition {
    @Override
    public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta) {
        return Runtime.version().feature() >= 17;
    }
}

@Configuration
public class FeatureConfig {
    @Bean
    @Conditional(Jdk17Condition.class)
    public MessageSender jdkSender() { return new LogSender(); }
}

// 启动:-Dspring.profiles.active=dev → 只有 LogSender 被注册

注意点

  • 条件方法/类在“刷新容器、实例化 Bean 前”评估:@Conditional 作用于 @Bean 方法时,条件 false 则整个方法跳过。
  • 一个 profile 都没激活时,带 @Profile 的 Bean 全部不注册;靠 @Profile("dev | prod") 兜底不要误以为有默认值。
  • 自定义 Condition.matches 里别做重量级 IO;它可能被多次调用。
  • 条件只决定“注册与否”,被跳过 Bean 的依赖方若没有替代 Bean,启动时会因找不到依赖而失败——注意成组设计。
  • Boot 下 @Profile@ConditionalOnProperty 常组合使用,前者管环境、后者管开关。

小结

@Profile 是环境维度的高层开关(dev/prod…),@Conditional 是底层通用机制(任意条件)。理解“条件在 Bean 实例化前评估、false 即跳过注册”这一点,就能解释环境相关 Bean 的装配行为,也是 Boot 自动配置的灵魂。

笔记加载中…