Spring:@Profile 注解用法介绍

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 参数指定环境外,我们还可以通过代码来动态控制激活的环境。

  1. 首先,创建一个 AnnotationConfigApplicationContext
  2. 设置环境变量,指定要激活的环境。
  3. 注册配置类。
  4. 启动时刷新容器。
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());
    }
}

解析

  1. @Profile(“onlineorder”):这个注解将 LogSchedule 类限定为在 onlineorder 环境下才会生效。只有当 Spring 容器中激活了 onlineorder 环境时,这个类中的任务才会被创建和执行。其他环境下这个类的任务不会被加载。

  2. @Scheduled(cron = “0 */1 * * * ?”):此注解表示每分钟执行一次 handleProcessLog 方法。cron 表达式 0 */1 * * * ? 代表每分钟的第 0 秒执行任务。

  3. @Scheduled(cron = “0 */2 * * * ?”):同样,handleQuality 方法的任务每 2 分钟执行一次。

  4. 日志记录:使用 @Slf4j 注解,Spring 会为类提供一个 log 对象,用于输出日志。每次定时任务执行时,都会记录日志,帮助我们跟踪任务的执行情况。

  5. 自动注入依赖:使用 @Autowired 注解自动注入 JpPropertiesILogProcessService,分别用于获取配置和执行日志处理。

具体使用场景

假设在 线上订单 环境下,系统需要定时处理订单相关的日志和质量检查任务。在这种情况下,可以使用 @Profile("onlineorder") 来确保这些任务只在该环境下执行。这样,在其他环境(如开发环境或测试环境)中,这些任务就不会被执行,从而避免了不必要的资源消耗。

如何激活环境

在 Spring 中,你可以通过多种方式激活 @Profile 注解所标注的环境:

1. 通过 JVM 参数 激活

启动应用时,通过 JVM 参数指定要激活的环境:

-Dspring.profiles.active=onlineorder
2. 通过 配置文件 激活

application.propertiesapplication.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();

五、使用总结

  1. @Profile 注解:Spring 中的 @Profile 注解帮助我们在不同的环境下配置不同的 bean,例如在开发环境、测试环境和生产环境中使用不同的数据源。
  2. 激活环境:可以通过 JVM 参数、代码配置或属性文件来激活特定的环境。
  3. 环境选择:通过 @Profile 注解标注的 bean 只有在指定的环境被激活时才会生效。

通过 @Profile 注解,Spring 提供了一种灵活的方式来管理多环境配置,避免了在代码中硬编码环境相关的设置,使得开发、测试和生产环境的切换变得更加方便。

希望通过这篇文章,你能更好地理解并运用 @Profile 注解,提高项目中的配置管理效率。如果你有任何问题,欢迎在评论区讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我心向阳iu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值