Spring Boot Profiles 指南

Spring Profiles 简介

通常,软件应用程序会在不同的环境中运行。在开发过程中,它将在 local 环境运行,然后我们可能会将它部署到 QAStagingPerformance 环境中,最后再部署到 Production 环境中。在不同环境中运行应用程序时,你可能需要用不同的配置属性来配置应用程序。

例如,如果你使用了数据库,那么你可以在开发过程中将数据库连接属性配置为本地运行的数据库。在 QA、Staging、Performance 和 Production 环境中部署时,则需要将数据库属性配置为特定环境的数据库。

Spring 为 application properties 的外部化提供了强大的支持,因此我们可以在不同的环境中运行时配置不同的属性。

为了使其更简单,我们可以使用 Spring Profiles 机制。使用不同的 profile 来配置 application properties,然后根据需要启用所需的 profile。

使用 properties 配置 Profile

假设我们正在构建一个使用 PostgreSQL 数据库的 Spring Boot 应用程序。我们希望在本地运行应用程序,使用在笔记本电脑上运行的 PostgreSQL 数据库。此外,我们还希望将应用程序部署到 QA 和 Production 环境中。

我们可以在默认的 properties 文件 src/main/resources/application.properties 中配置默认属性,如下所示:

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres

我们可以在 src/main/resources/application-{profile}.{properties/yml} 文件中配置任何特定 profile 的属性,当你激活该 profile 时,Spring Boot 会自动使用该 profile 的属性。因此,我们可以按照以下方式在 src/main/resources/application-qa.properties 中配置 QA profile 的属性:

spring.datasource.url=jdbc:postgresql://postgres_qa:5432/postgres
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

qa profile 配置文件中,我们配置了指向远程数据库 postgres_qa 的 JDBC URL。usernamepassword 分别配置为使用环境变量 DB_USERNAMEDB_PASSWORD

如果你觉得为不同的 profile 创建单独的 properties 文件比较麻烦,那你可以将所有 profile 的 properties 放在 application.properties 文件中,使用 #---!--- 分隔符将进行分割,如下所示:

application.properties:

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres

#---
spring.config.activate.on-profile=qa
spring.datasource.url=jdbc:postgresql://postgres_qa:5432/postgres
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

在 Configuration 类中指定 Profiles

Profile 的支持不仅限于配置属性。我们还可以在 Spring Configuration 类中使用 profile 来注册 Bean,如下所示:

@Configuration
class RepositoriesConfiguration {
    
    @Bean
    @Profile("jdbc")
    UserRepository jdbcUserRepository() {
        return new JdbcUserRepository();
    }

    @Bean
    @Profile("mongo")
    UserRepository mongoUserRepository() {
        return new MongoUserRepository();
    }
}

在这个 Spring 配置类中,我们注册了 2 个不同的 UserRepository Bean,但使用了不同的 profile。现在,当使用 jdbc profile 启动应用时,将注册 JdbcUserRepository 实例。如果启用了 mongo profile,则将注册 MongoUserRepository 实例。

除了在 @Bean 方法上注解 @Profile 之外,我们还可以在 @Configuration 类的类上使用 @Profile。在这种情况下,在该类中注册的所有 Bean 都将与该 profile 相关联,并且只有在该 profile 处于活动状态时才会在 ApplicationContext 中注册。

使用 Profile 表达式

使用 @Profile 注解可以关联多 profile,如下所示:

@Configuration
class RepositoriesConfiguration {
    @Bean
    @Profile({"mongo", "cloud"})
    UserRepository mongoUserRepository() {
        return new MongoUserRepository();
    }
}

在此示例中,如果激活了 mongocloud profile,则将注册 MongoUserRepository Bean。

除了关联多个 profile 外,我们还可以使用 profile 表达式来实现复杂的 Bean 注册需求。

@Configuration
class RepositoriesConfiguration {
    @Bean
    @Profile({"mongo & cloud", "docker", "!jdbc"})
    UserRepository mongoUserRepository() {
        return new MongoUserRepository();
    }
}

如你所见,我们还可以使用逻辑操作符 &|! 。在上面的示例中,如果以下条件至少有一个为 trueMongoUserRepository Bean 就会被注册:

  • 同时启用 mongocloud profile。
  • 启用 docker profile。
  • 未启用 jdbc profile。

注意:如果你定义了一个 bean,但没有关联到任何 profile,那么该 bean 将关联到 default profile,默认情况下该 profile 处于活动状态。

虽然 profile 表达式提供了更多配置 profile 的功能,但切勿过度使用 profile。否则,你很快就会发现自己不知道在哪种情况下要注册哪个 Bean。

如何激活 Spring Profiles

定义好 profile 配置文件和 Bean 后,我们需要激活 profile,以启用特定 profile 的配置。

启用 profile 的常用方法是使用 SPRING_PROFILES_ACTIVE 环境变量。

$ export SPRING_PROFILES_ACTIVE=mongo
$ java -jar app.jar

$ SPRING_PROFILES_ACTIVE=docker,jdbc java -jar app.jar

你还可以使用 spring.profiles.active 系统属性启用 profile,如下所示:

$ java -Dspring.profiles.active=docker,jdbc -jar app.jar

在测试中,可以使用 @ActiveProfiles 注解启用 profile,具体如下:

@SpringBootTest
@ActiveProfiles({"test", "integration-test"})
class CustomerControllerTest {

  @Test
  void testSomething() {
      ...
  }
}

如果你没有激活任何 profile,那么 default profile 将处于活动状态,你可以在应用日志中看到它,如下所示:

2023-07-29T09:55:53.709+05:30  INFO 4338 --- [  restartedMain] c.s.h.Application    : Starting Application using Java 17.0.4.1 with PID 4338...
2023-07-29T09:55:53.710+05:30  INFO 4338 --- [  restartedMain] c.s.h.Application    : No active profile set, falling back to 1 default profile: "default"
...
...

如果启用 dockerjdbc profile 并启动应用,就可以在应用日志中看到已激活的 profile,如下所示:

2023-07-29T09:55:53.709+05:30  INFO 4338 --- [  restartedMain] c.s.h.Application    : Starting Application using Java 17.0.4.1 with PID 4338...
2023-07-29T09:55:53.710+05:30  INFO 4338 --- [  restartedMain] c.s.h.Application    : The following 2 profiles are active: "docker", "jdbc"
...
...

总结

在本教程中,我们学习了如何通过 spring profiles 来定义不同环境下的配置属性,以及根据不同 profile 注册 bean 和激活 profile 的方式。

虽然 Spring Profiles 很方便,但过度使用会让人对应用程序配置的理解变得混乱。


参考:https://www.sivalabs.in/spring-boot-profiles-tutorial/