1. 概述
在本教程中,我们将着重介绍 Spring 中的 Profiles。
Profiles是框架的核心功能——允许我们将 bean 映射到不同的Profile——例如,dev、test 和 prod。
然后我们可以在不同的环境中激活不同的Profiles以仅引导我们需要的 bean。
2. 在 Bean 上使用
@Profile
让我们从简单开始,看看如何让一个 bean 属于一个特定的Profile。 **我们使用
@Profile
注解—我们将 bean 映射到那个特定的Profile**; 注解采用一个(或多个)Profile的名称。
考虑一个基本场景:我们有一个 bean,它应该只在开发期间处于活动状态,但不能部署在生产环境中。
我们用 @Profile(“dev”) 注解该 bean,它只会在开发期间出现在容器中。 在生产中,dev 根本不会激活:
@Component@Profile("dev")publicclassDevDatasourceConfig
作为快速旁注,Profile名称也可以使用 NOT 运算符作为前缀,例如
!dev
,以将它们从Profile中排除。
在示例中,仅当 dev Profile未激活时才激活该组件:
@Component@Profile("!dev")publicclassDevDatasourceConfig
3. 在 XML 中声明Profiles
Profiles can also be configured in XML. The tag has a profile attribute, which takes comma-separated values of the applicable profiles:
<beansprofile="dev"><beanid="devDatasourceConfig"class="org.baeldung.profiles.DevDatasourceConfig"/></beans>
4. 设置 Profiles
下一步是激活和设置Profiles,以便在容器中注册相应的 bean。
这可以通过多种方式完成,我们将在以下部分中进行探讨。
4.1. 通过
WebApplicationInitializer
接口以编程方式
在 Web 应用程序中,WebApplicationInitializer 可用于以编程方式配置 ServletContext。
这也是一个非常方便的位置,可以通过编程方式设置我们的激活的profiles:
@ConfigurationpublicclassMyWebApplicationInitializerimplementsWebApplicationInitializer{@OverridepublicvoidonStartup(ServletContext servletContext)throwsServletException{
servletContext.setInitParameter("spring.profiles.active","dev");}}
4.2. 通过
ConfigurableEnvironment
以编程方式
我们还可以直接在environment中设置profiles:
@AutowiredprivateConfigurableEnvironment env;...
env.setActiveProfiles("someProfile");
4.3.
web.xml
中的上下文参数
同样,我们可以使用上下文参数在 Web 应用程序的 web.xml 文件中定义活动Profile:
<context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/app-config.xml</param-value></context-param><context-param><param-name>spring.profiles.active</param-name><param-value>dev</param-value></context-param>
4.4. JVM 系统参数
profile名称也可以通过 JVM 系统参数传入。 这些profile将在应用程序启动期间被激活:
-Dspring.profiles.active=dev
4.5. 环境变量
在 Unix 环境下,profiles 也可以通过环境变量激活:
export SPRING_PROFILES_ACTIVE=dev
//或者
export spring_profiles_active=dev
4.6. Maven Profile
Spring Profile也可以通过 Maven Profile激活,方法是**指定
spring.profiles.active
配置属性**。
在每个 Maven Profile中,我们可以设置一个 spring.profiles.active 属性:
<profiles><profile><id>dev</id><activation><activeByDefault>true</activeByDefault></activation><properties><spring.profiles.active>dev</spring.profiles.active></properties></profile><profile><id>prod</id><properties><spring.profiles.active>prod</spring.profiles.active></properties></profile></profiles>
**它的值将用于替换
application.properties
文件中
@spring.profiles.active@
的占位符 :**
[email protected]@
现在我们需要在 pom.xml 中启用资源过滤:
<build><resources><resource><filtering>true</filtering><directory>src/main/resources</directory><includes><include>public/**</include><include>static/**</include><include>templates/**</include><include>tpl/**</include><include>application.*</include><include>application-${spring.profiles.active}.*</include><include>log*-${spring.profiles.active}.xml</include></includes></resource></resources>
...
</build>
并附加一个 -P 参数来切换将应用哪个 Maven Profile:
mvn clean package -Pprod
此命令将为 prod Profile打包应用程序。 它还会在应用程序运行时应用 spring.profiles.active 值为 prod。
4.7.
@ActiveProfile
在测试中
使用 @ActiveProfile 注解启用特定profile,测试可以很容易地指定哪些profile处于活动状态:
@ActiveProfiles("dev")
到目前为止,我们已经研究了多种激活Profile的方法。 现在让我们看看哪个优先级高于另一个,如果我们使用多个优先级从高到低会发生什么:
- web.xml 文件里的上下文参数
- WebApplicationInitializer接口
- JVM 系统参数
- 环境变量
- Maven profile
5. 默认的 Profile
任何未指定profile的 bean 都属于 default profile。
Spring 还提供了一种在没有其他profile处于活动状态时设置默认profile的方法—通过使用 spring.profiles.default 属性。
6. 获取活动Profile
Spring 的活动Profile驱动 @Profile 注解的行为以启用/禁用 beans。 但是,我们也可能希望以编程方式访问活动profile列表。
我们有两种方法,**使用
Environment
或
spring.profiles.active
**。
6.1. 使用 Environment
我们可以通过注入 Environment 对象访问活动profiles:
publicclassProfileManager{@AutowiredprivateEnvironment environment;publicvoidgetActiveProfiles(){for(String profileName : environment.getActiveProfiles()){System.out.println("Currently active profile - "+ profileName);}}}
6.2. 使用
spring.profiles.active
或者,我们可以通过注入属性 spring.profiles.active 来访问profile:
@Value("${spring.profiles.active}")privateString activeProfile;
在这里,我们的 activeProfile 变量将包含当前处于活动状态的profile的名称,如果有多个,它将包含以逗号分隔的名称。
但是,我们应该考虑如果根本没有活动profile会发生什么情况。对于我们上面的代码,缺少profile将阻止创建应用程序上下文。 由于缺少用于注入变量的占位符,这将导致抛出 IllegalArgumentException。
为了避免这种情况,我们可以定义一个默认值:
@Value("${spring.profiles.active:}")privateString activeProfile;
现在,如果没有Profile处于活动状态,我们的 activeProfile 将只包含一个空字符串。
如果我们想像前面的示例一样访问它们的列表,我们可以通过拆分 activeProfile 变量来实现:
publicclassProfileManager{@Value("${spring.profiles.active:}")privateString activeProfiles;publicStringgetActiveProfiles(){for(String profileName : activeProfiles.split(",")){System.out.println("Currently active profile - "+ profileName);}}}
7. 示例:使用Profiles分离数据源配置
既然已经了解了基础知识,让我们来看一个真实的例子。
考虑这样一个场景,我们必须为开发和生产环境维护数据源配置。
让我们创建一个公共接口 DatasourceConfig ,它需要由两个数据源实现来实现:
publicinterfaceDatasourceConfig{publicvoidsetup();}
下面是开发环境的配置:
@Component@Profile("dev")publicclassDevDatasourceConfigimplementsDatasourceConfig{@Overridepublicvoidsetup(){System.out.println("Setting up datasource for DEV environment. ");}}
以及生产环境的配置:
@Component@Profile("production")publicclassProductionDatasourceConfigimplementsDatasourceConfig{@Overridepublicvoidsetup(){System.out.println("Setting up datasource for PRODUCTION environment. ");}}
现在让我们创建一个测试并注入我们的 DatasourceConfig 接口; 根据活动profile,Spring 将注入 DevDatasourceConfig 或 ProductionDatasourceConfig bean:
publicclassSpringProfilesWithMavenPropertiesIntegrationTest{@AutowiredDatasourceConfig datasourceConfig;publicvoidsetupDatasource(){
datasourceConfig.setup();}}
当 dev profile 处于活动状态时,Spring 注入 DevDatasourceConfig 对象,然后调用 setup() 方法时,输出如下:
Setting up datasource for DEV environment.
8. Spring Boot 中的Profiles
Spring Boot 支持到目前为止概述的所有profile配置,并具有一些附加功能。
8.1. 激活或设置一个Profile
第 4 节中介绍的初始化参数 spring.profiles.active 也可以设置为 Spring Boot 中的一个属性来定义当前活动的profiles。 这是 Spring Boot 将自动获取的标准属性:
spring.profiles.active=dev
但是,从 Spring Boot 2.4 开始,此属性不能与 spring.config.activate.on-profile 一起使用,因为这可能会引发 ConfigDataException(即**InvalidConfigDataPropertyException 或 InactiveConfigDataAccessException)。
要以编程方式设置profiles,我们还可以使用 SpringApplication 类:
SpringApplication.setAdditionalProfiles("dev");
要在 Spring Boot 中使用 Maven 设置Profile,我们可以在 pom.xml 中的 spring-boot-maven-plugin 下指定Profile名称:
<plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><profiles><profile>dev</profile></profiles></configuration></plugin>
...
</plugins>
并执行特定于 Spring Boot 的 Maven 目标:
mvn spring-boot:run
8.2.特定于Profile的属性文件
然而,Spring Boot 带来的最重要的Profile相关功能是特定于Profile的属性文件。这些文件必须以 application-{profile}.properties 格式命名。
Spring Boot 将自动为所有profiles加载 application.properties 文件中的属性,并仅为指定的profile加载特定于profiles的 .properties 文件中的属性。
例如,我们可以使用名为 application-dev.properties 和 application-production.properties 的两个文件为 dev 和 production profile配置不同的数据源:
在 application-production.properties 文件中,我们可以设置一个 MySql 数据源:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=root
然后我们可以在 application-dev.properties 文件中为 dev Profile配置相同的属性,以使用内存中的 H2 数据库:
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
这样我们就可以很方便的为不同的环境提供不同的配置。
在 Spring Boot 2.4 之前,可以从特定于Profile的文档中激活Profile。 但情况已不再如此; 对于更高版本,在这些情况下,框架将再次抛出 InvalidConfigDataPropertyException 或 InactiveConfigDataAccessException。
8.3. 多文档文件
为了进一步简化为单独环境定义属性,我们甚至可以将所有属性组合在同一个文件中,并使用分隔符来指示Profile。
从 2.4 版开始,Spring Boot 除了以前支持的 YAML 之外,还扩展了对属性文件的多文档文件的支持。 所以现在,我们可以在同一个 application.properties 中指定
dev
和
production
属性:
my.prop=used-always-in-all-profiles
#---
spring.config.activate.on-profile=dev
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=root
#---
spring.config.activate.on-profile=production
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
该文件由 Spring Boot 按从上到下的顺序读取。 也就是说,如果某些属性,比如 my.prop,在上面的示例中再次出现在末尾,则将考虑最末端的值。
8.4. Profile 组
Spring Boot 2.4 中添加的另一个功能是配置Profile组。 顾名思义,它允许我们将相似的Profile分组在一起。
让我们考虑一个用例,其中我们有多个生产环境的profiles。 比如,proddb 用于数据库,prodquartz 用于 production 环境中的调度程序。
要通过我们的 application.properties 文件同时启用这些Profile,我们可以指定:
spring.profiles.group.production=proddb,prodquartz
因此,激活 production Profile也会激活 proddb 和 prodquartz。
<<<<<< [完] >>>>>>
版权归原作者 爱游泳的老白 所有, 如有侵权,请联系我们删除。