Spring:@Profile 注解用法介绍
本文将深入探讨 Spring 中的 @Profile 注解,展示它在不同环境配置和动态选择不同 bean
实例方面的使用方法。我们会通过简单的示例来讲解如何通过 @Profile
注解配置不同的数据源,并且展示如何在开发环境、测试环境和生产环境中动态选择不同的数据源。
一、@Profile 注解的作用
在 Spring 框架中,@Profile
注解非常适合用来根据不同的环境来选择不同的 bean
配置。它在 Spring 应用中可以指定某个 bean
只在特定环境下生效,从而使得在不同的开发、测试和生产环境中,能够灵活地使用不同的配置。
@Profile
注解通常用于以下场景:
- 在不同的环境下使用不同的 数据源。
- 配置不同的 服务端口。
- 配置不同的 消息队列。
最典型的例子是:在开发环境、测试环境和生产环境下配置不同的数据库连接。通过使用 @Profile
注解,我们可以避免在代码中硬编码不同环境的配置,而是通过 Spring 的容器管理,在不同环境下选择不同的配置。
二、@Profile 指定环境的方式
2.1 JVM 启动参数
可以在启动 Java 应用时,通过虚拟机参数 -Dspring.profiles.active
来指定要激活的环境。例如,在开发环境中启动时可以使用以下命令:
-Dspring.profiles.active=dev
在此情况下,Spring 容器会根据 @Profile
注解标记的环境来激活对应的配置类。
2.2 通过代码方式控制
除了在启动时通过 JVM 参数指定环境外,我们还可以通过代码来动态控制激活的环境。
- 首先,创建一个
AnnotationConfigApplicationContext
。 - 设置环境变量,指定要激活的环境。
- 注册配置类。
- 启动时刷新容器。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev", "onLine");
context.register(TestProfileConfig.class);
context.refresh();
三、@Profile 实现切换数据源示例
在实际项目中,我们经常需要根据不同的环境选择不同的数据源配置。下面通过一个示例,展示如何通过 @Profile
注解来切换不同环境的数据源。
3.1 导入依赖
首先,我们需要引入一些常用的数据库依赖,下面是 Maven 配置中的依赖:
<!-- C3P0 数据源依赖 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- MySQL JDBC 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
3.2 新建数据源配置文件 dataSource.properties
我们可以将数据库的配置信息放到一个属性文件中,例如 dataSource.properties
,内容如下:
dataSource.user=root
dataSource.password=123
dataSource.driverClassName=com.mysql.jdbc.Driver
3.3 新建配置类 TestProfileConfig.java
我们创建一个配置类 TestProfileConfig
,并使用 @Profile
注解标注不同的环境数据源配置:
package com.spring.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@PropertySource("classpath:/dataSource.properties")
@Configuration
public class TestProfileConfig {
@Value("${dataSource.user}")
private String user;
private String driverClassName;
// 开发环境数据源配置
@Profile("dev")
@Bean
public DataSource dataSourceDev(@Value("${dataSource.password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev_db");
dataSource.setDriverClass(driverClassName);
return dataSource;
}
// 测试环境数据源配置
@Profile("test")
@Bean
public DataSource dataSourceTest(@Value("${dataSource.password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_db");
dataSource.setDriverClass(driverClassName);
return dataSource;
}
// 生产环境数据源配置
@Profile("online")
@Bean
public DataSource dataSourceOnLine(@Value("${dataSource.password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/online_db");
dataSource.setDriverClass(driverClassName);
return dataSource;
}
// 使用 StringValueResolver 解析配置中的 driverClassName
public void setEmbeddedValueResolver(StringValueResolver resolver) {
driverClassName = resolver.resolveStringValue("${dataSource.driverClassName}");
}
}
3.4 新建测试类 TestProfile.java
最后,我们创建一个测试类 TestProfile.java
来演示如何根据不同环境加载不同的数据源配置:
package com.spring.test;
import com.spring.config.TestProfileConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
public class TestProfile {
public static void main(String[] args) {
// 创建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev", "online"); // 激活多个环境配置
context.register(TestProfileConfig.class);
context.refresh();
// 获取并打印所有的 DataSource bean
String[] names = context.getBeanNamesForType(DataSource.class);
for (String name : names) {
System.out.println(name);
}
}
}
输出结果:
dataSourceDev
dataSourceOnLine
四、实际案例:基于 @Profile
注解的定时任务配置
在实际开发中,我们通常需要根据不同的环境来配置一些任务,特别是定时任务。在 Spring 中,@Profile
注解可以与 @Scheduled
注解结合使用,来在特定环境下启用或禁用某些任务。下面的示例展示了如何使用 @Profile
注解来控制定时任务只在特定环境下执行。
示例代码解析
@Slf4j
@Component
@Profile("onlineorder") // 只在 "onlineorder" 环境下启用此类
public class LogSchedule {
@Autowired
private Properties jpProperties;
@Autowired
private ILogProcessService logProcessService;
// 每分钟执行一次日志处理任务
@Scheduled(cron = "0 */1 * * * ?")
public void handleProcessLog() {
logProcessService.processLog();
log.info("Log processing completed at: " + System.currentTimeMillis());
}
// 每两分钟执行一次质量处理任务
@Scheduled(cron = "0 */2 * * * ?")
public void handleQuality() {
//logService.processQuality();
log.info("Quality processing task executed at: " + System.currentTimeMillis());
}
}
解析
-
@Profile(“onlineorder”):这个注解将
LogSchedule
类限定为在onlineorder
环境下才会生效。只有当 Spring 容器中激活了onlineorder
环境时,这个类中的任务才会被创建和执行。其他环境下这个类的任务不会被加载。 -
@Scheduled(cron = “0 */1 * * * ?”):此注解表示每分钟执行一次
handleProcessLog
方法。cron
表达式0 */1 * * * ?
代表每分钟的第 0 秒执行任务。 -
@Scheduled(cron = “0 */2 * * * ?”):同样,
handleQuality
方法的任务每 2 分钟执行一次。 -
日志记录:使用
@Slf4j
注解,Spring 会为类提供一个log
对象,用于输出日志。每次定时任务执行时,都会记录日志,帮助我们跟踪任务的执行情况。 -
自动注入依赖:使用
@Autowired
注解自动注入JpProperties
和ILogProcessService
,分别用于获取配置和执行日志处理。
具体使用场景
假设在 线上订单 环境下,系统需要定时处理订单相关的日志和质量检查任务。在这种情况下,可以使用 @Profile("onlineorder")
来确保这些任务只在该环境下执行。这样,在其他环境(如开发环境或测试环境)中,这些任务就不会被执行,从而避免了不必要的资源消耗。
如何激活环境
在 Spring 中,你可以通过多种方式激活 @Profile
注解所标注的环境:
1. 通过 JVM 参数 激活
启动应用时,通过 JVM 参数指定要激活的环境:
-Dspring.profiles.active=onlineorder
2. 通过 配置文件 激活
在 application.properties
或 application.yml
中配置激活的环境:
application.properties
spring.profiles.active=onlineorder
application.yml
spring:
profiles:
active: onlineorder
3. 通过 代码方式 激活
通过代码在 AnnotationConfigApplicationContext
中指定激活的环境:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("onlineorder");
context.register(LogSchedule.class);
context.refresh();
五、使用总结
- @Profile 注解:Spring 中的
@Profile
注解帮助我们在不同的环境下配置不同的bean
,例如在开发环境、测试环境和生产环境中使用不同的数据源。 - 激活环境:可以通过 JVM 参数、代码配置或属性文件来激活特定的环境。
- 环境选择:通过
@Profile
注解标注的bean
只有在指定的环境被激活时才会生效。
通过 @Profile
注解,Spring 提供了一种灵活的方式来管理多环境配置,避免了在代码中硬编码环境相关的设置,使得开发、测试和生产环境的切换变得更加方便。
希望通过这篇文章,你能更好地理解并运用 @Profile
注解,提高项目中的配置管理效率。如果你有任何问题,欢迎在评论区讨论!