Spring条件装配
Spring条件装配[编辑 | 编辑源代码]
概述[编辑 | 编辑源代码]
Spring条件装配(Conditional Bean Registration)是Spring Framework 4.0引入的核心特性,允许开发者根据特定条件动态控制Bean的注册行为。通过条件装配,可以实现:
- 环境适配(如开发/生产环境配置切换)
- 类路径依赖检测
- 系统属性判断
- 自定义条件逻辑
条件装配通过@Conditional
注解实现,其核心接口为Condition
,Spring Boot进一步扩展了此机制,提供了@ConditionalOnClass
、@ConditionalOnProperty
等便捷注解。
核心机制[编辑 | 编辑源代码]
基础接口[编辑 | 编辑源代码]
Spring条件装配的核心接口位于org.springframework.context.annotation
包中:
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
当matches()
返回true
时,关联的Bean才会被注册。
工作流程[编辑 | 编辑源代码]
使用方式[编辑 | 编辑源代码]
1. 基本条件装配[编辑 | 编辑源代码]
示例:仅当系统属性"mode=prod"时注册Bean
public class ProductionCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return "prod".equals(context.getEnvironment().getProperty("mode"));
}
}
@Configuration
public class AppConfig {
@Bean
@Conditional(ProductionCondition.class)
public DataSource productionDataSource() {
return new HikariDataSource();
}
}
2. Spring Boot条件注解[编辑 | 编辑源代码]
Spring Boot提供了更便捷的条件注解:
@Configuration
public class CacheConfig {
@Bean
@ConditionalOnClass(RedisClient.class)
public RedisCacheService redisCache() {
return new RedisCacheService();
}
@Bean
@ConditionalOnMissingClass("com.redis.RedisClient")
public LocalCacheService localCache() {
return new LocalCacheService();
}
}
常用Spring Boot条件注解:
@ConditionalOnProperty
- 根据配置属性判断@ConditionalOnBean
- 根据已存在Bean判断@ConditionalOnWebApplication
- Web环境判断@ConditionalOnExpression
- SpEL表达式判断
进阶应用[编辑 | 编辑源代码]
组合条件[编辑 | 编辑源代码]
通过@Conditional
实现AND逻辑:
public class AllConditions implements Condition {
private final Condition[] conditions;
public AllConditions(Condition... conditions) {
this.conditions = conditions;
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return Arrays.stream(conditions)
.allMatch(condition -> condition.matches(context, metadata));
}
}
条件元数据[编辑 | 编辑源代码]
通过AnnotatedTypeMetadata
访问注解属性:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnServiceCondition.class)
public @interface ConditionalOnService {
String value();
}
public class OnServiceCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(
ConditionalOnService.class.getName());
String serviceName = (String) attributes.get("value");
// 检查服务是否可用...
}
}
实际案例[编辑 | 编辑源代码]
多环境配置[编辑 | 编辑源代码]
根据不同环境加载不同的数据源配置:
@Configuration
public class DataSourceConfig {
@Bean
@ConditionalOnProperty(name = "env", havingValue = "dev")
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
@ConditionalOnProperty(name = "env", havingValue = "prod")
public DataSource prodDataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://prod-db:3306/app")
.username("prod_user")
.password("securePass123")
.build();
}
}
功能开关[编辑 | 编辑源代码]
实现基于配置的功能开关:
@Configuration
public class FeatureConfig {
@Bean
@ConditionalOnProperty(
value = "features.analytics.enabled",
havingValue = "true",
matchIfMissing = false)
public AnalyticsService analyticsService() {
return new GoogleAnalyticsService();
}
}
数学表达[编辑 | 编辑源代码]
条件概率在配置决策中的应用:
最佳实践[编辑 | 编辑源代码]
1. 优先使用Spring Boot提供的条件注解
2. 复杂条件逻辑应封装为独立Condition
实现
3. 避免条件冲突(多个条件匹配同一Bean)
4. 在@Configuration
类上使用条件注解可控制整个配置类的加载
5. 使用spring-boot-autoconfigure
作为条件注解设计参考
常见问题[编辑 | 编辑源代码]
Q: 条件注解与@Profile有什么区别?
A: @Profile
是特殊的条件实现,仅基于spring.profiles.active判断,而条件注解更灵活,可以处理任意条件逻辑。
Q: 如何调试条件装配失败?
A: 启动时添加-Ddebug
参数,Spring Boot会输出详细的条件评估报告。