Spring @Profile注解详解
Spring @Profile注解详解
一、基本概念
@Profile注解用于在不同环境下启用不同的Bean或配置类。它允许我们根据当前激活的profile来决定哪些Bean应该被创建,哪些不应该被创建。
二、基本使用
1. 在配置类上使用
@Configuration
@Profile("dev")
public class DevConfig {
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://localhost:3306/dev_db")
.username("dev")
.password("dev123")
.build();
}
}
@Configuration
@Profile("prod")
public class ProdConfig {
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://prod-server:3306/prod_db")
.username("prod")
.password("prod123")
.build();
}
}
2. 在Bean方法上使用
@Configuration
public class AppConfig {
@Bean
@Profile("dev")
public EmailService mockEmailService() {
return new MockEmailService();
}
@Bean
@Profile("prod")
public EmailService realEmailService() {
return new RealEmailService();
}
}
3. 在组件类上使用
@Service
@Profile("dev")
public class DevServiceImpl implements MyService {
// 开发环境实现
}
@Service
@Profile("prod")
public class ProdServiceImpl implements MyService {
// 生产环境实现
}
三、Profile的激活方式
1. 配置文件方式
# application.yml
spring:
profiles:
active: dev
group:
dev: dev-db, dev-mq
prod: prod-db, prod-mq
2. 命令行方式
java -jar app.jar --spring.profiles.active=dev
3. 编程方式
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setAdditionalProfiles("dev");
app.run(args);
}
}
四、Profile的实现原理
1. 核心类和接口
// Spring的核心接口和类
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
boolean acceptsProfiles(Profiles profiles);
}
public interface ConfigurableEnvironment extends Environment {
void setActiveProfiles(String... profiles);
void addActiveProfile(String profile);
void setDefaultProfiles(String... profiles);
}
// Profile条件判断
public class ProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 获取@Profile注解的值
MultiValueMap<String, Object> attrs =
metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
String[] profiles = (String[]) attrs.getFirst("value");
// 检查是否匹配当前激活的profile
return context.getEnvironment()
.acceptsProfiles(Profiles.of(profiles));
}
return true;
}
}
2. 注解处理过程
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}
3. 配置处理过程
public class AnnotationConfigApplicationContext extends GenericApplicationContext {
private final AnnotatedBeanDefinitionReader reader;
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
// 注册配置类
}
@Override
protected void prepareRefresh() {
// 准备Environment
ConfigurableEnvironment env = getEnvironment();
// 配置激活的profiles
}
}
五、高级用法
1. 组合Profile
@Configuration
public class MultiProfileConfig {
@Bean
@Profile({"dev", "test"})
public DataSource devTestDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
@Profile("!dev & !test")
public DataSource productionDataSource() {
// 生产环境数据源
return new DriverManagerDataSource();
}
}
2. Profile表达式
@Configuration
public class ProfileExpressionConfig {
@Bean
@Profile("dev | test") // dev或test环境
public SecurityConfig devSecurityConfig() {
return new DevSecurityConfig();
}
@Bean
@Profile("prod & !eu") // 生产环境但不是欧盟区
public SecurityConfig prodSecurityConfig() {
return new ProdSecurityConfig();
}
}
3. 默认Profile
@Configuration
public class DefaultProfileConfig {
@Bean
@Profile("default") // 当没有激活的profile时使用
public DataSource defaultDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
六、实际应用示例
1. 多环境配置管理
@Configuration
public class MultiEnvironmentConfig {
@Bean
@Profile("dev")
public LoggingService devLogging() {
return new DetailedLoggingService();
}
@Bean
@Profile("prod")
public LoggingService prodLogging() {
return new MinimalLoggingService();
}
@Bean
@Profile("dev")
public CacheConfig devCache() {
return new LocalCacheConfig();
}
@Bean
@Profile("prod")
public CacheConfig prodCache() {
return new DistributedCacheConfig();
}
}
2. 测试配置
@SpringBootTest
@ActiveProfiles("test")
public class ServiceTest {
@Autowired
private MyService service;
@Test
public void testWithTestProfile() {
// 使用测试环境的配置进行测试
}
}
3. 条件化配置
@Configuration
public class ConditionalConfig {
@Bean
@Profile("dev")
@ConditionalOnProperty(name = "debug", havingValue = "true")
public DebugService debugService() {
return new DebugServiceImpl();
}
@Bean
@Profile("prod")
@ConditionalOnClass(name = "com.amazonaws.services.s3.AmazonS3")
public StorageService s3StorageService() {
return new S3StorageService();
}
}
Profile注解的处理过程:
- Spring容器启动时,首先准备Environment
- 读取配置文件和命令行参数,确定激活的profiles
- 在处理@Configuration类时,通过ProfileCondition检查@Profile注解
- 根据当前激活的profiles决定是否创建相应的Bean
- 在整个应用生命周期中维护profile状态
使用建议:
- 合理规划profile的粒度
- 使用有意义的profile名称
- 避免过度使用profile
- 提供合适的默认配置
- 记录profile的使用文档
通过正确使用@Profile注解,可以实现灵活的环境配置管理,提高应用的可维护性和部署效率。
本文来自博客园,作者:Eular,转载请注明原文链接:https://www.cnblogs.com/euler-blog/p/18786434
浙公网安备 33010602011771号