Spring @Profile注解详解
一、基本概念
@Profile注解用于在不同环境下启用不同的Bean或配置类。它允许我们根据当前激活的profile来决定哪些Bean应该被创建,哪些不应该被创建。
二、基本使用
1. 在配置类上使用
@Configuration
@Profile("dev")
public class DevConfig {@Beanpublic DataSource dataSource() {return DataSourceBuilder.create().url("jdbc:mysql://localhost:3306/dev_db").username("dev").password("dev123").build();}
}@Configuration
@Profile("prod")
public class ProdConfig {@Beanpublic 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: devgroup:dev: dev-db, dev-mqprod: 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 {@Overridepublic 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");// 检查是否匹配当前激活的profilereturn 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);// 注册配置类}@Overrideprotected void prepareRefresh() {// 准备EnvironmentConfigurableEnvironment 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 {@Autowiredprivate MyService service;@Testpublic 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注解,可以实现灵活的环境配置管理,提高应用的可维护性和部署效率。