@Conditional
核心机制
1. 核心接口:Condition
@FunctionalInterface
public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
matches()
方法返回true
则条件满足,对应的配置类或 Bean 被创建ConditionContext
提供了Environment
、BeanFactory
、ClassLoader
等上下文AnnotatedTypeMetadata
提供了注解的元数据(如属性值)
2. 标记注解:@Conditional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {Class<? extends Condition>[] value();
}
用于标记某个类或方法,只有当指定的 Condition
实现类返回 true
时才生效。
实战 1:自定义 @ConditionalOnPortOpen
需求
只有当 Redis 服务(端口 6379)可用时,才加载 RedisService
。
步骤 1:定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Conditional(PortOpenCondition.class)
public @interface ConditionalOnPortOpen {int port();String host() default "localhost";
}
步骤 2:实现 Condition
public class PortOpenCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnPortOpen.class.getName());int port = (Integer) attrs.get("port");String host = (String) attrs.get("host");try (Socket socket = new Socket()) {socket.connect(new InetSocketAddress(host, port), 2000); // 2秒超时return true;} catch (IOException e) {// 端口不通或超时return false;}}
}
步骤 3:使用
@Service
@ConditionalOnPortOpen(port = 6379, host = "redis-server")
public class RedisService {public void setData(String key, String value) { ... }
}
✅ Redis 服务宕机时,
RedisService
不会被创建,避免启动报错
实战 2:自定义“功能开关”注解 @ConditionalOnFeatureEnabled
需求
实现一个通用的功能开关,通过 application.yml
配置启用/禁用。
features:payment: truerecommendation: false
自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Conditional(FeatureEnabledCondition.class)
public @interface ConditionalOnFeatureEnabled {String name(); // 如 "payment"
}
Condition 实现
public class FeatureEnabledCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnFeatureEnabled.class.getName());String featureName = (String) attrs.get("name");Environment env = context.getEnvironment();// 读取 features.paymentreturn env.getProperty("features." + featureName, Boolean.class, false);}
}
使用
@Service
@ConditionalOnFeatureEnabled(name = "payment")
public class PaymentService { ... }@Service
@ConditionalOnFeatureEnabled(name = "recommendation")
public class RecommendationService { ... }
✅ 无需重启,修改配置即可动态开关功能!