补习系列(22)-全面解读 Spring Profile 的用法

1、简介

Profile的意思是配置,对于应用程序来讲,不一样的环境须要不一样的配置。
好比:java

  • 开发环境,应用须要链接一个可供调试的数据库单机进程
  • 生产环境,应用须要使用正式发布的数据库,一般是高可用的集群
  • 测试环境,应用只须要使用内存式的模拟数据库

Spring框架提供了多profile的管理功能,咱们能够使用profile功能来区分不一样环境的配置。web

2、 区分Bean对象

首先,咱们先看看如何基于Profile来定义一个Bean。spring

经过@Profile注解能够为一个Bean赋予对应的profile名称,以下:数据库

@Component
@Profile("dev")
public class DevDatasourceConfig

上面的DevDatasourceConfig被定义为 profile=dev,因而该Bean只会在dev(开发环境)模式下被启用。
若是须要定义为非dev环境,能够使用这样的形式:springboot

@Component
@Profile("!dev")
public class DevDatasourceConfig

XML风格配置
上面的例子也能够使用XML配置文件达到一样的目的,以下:app

<beans profile="dev">
    <bean id="devDatasourceConfig"
      class="org.baeldung.profiles.DevDatasourceConfig" />
</beans>

读取Profile
经过ConfigurableEnvironment这个Bean 能够得到当前的Profile,以下:框架

public class ProfileManager {
    @Autowired
    Environment environment;
 
    public void getActiveProfiles() {
        for (final String profileName : environment.getActiveProfiles()) {
            System.out.println("Currently active profile - " + profileName);
        }   
    }
}

3、 设置Profile

接下来,为了让容器"仅仅注册那些所须要的Bean",咱们须要经过一些手段来设置当前的profile。webapp

有不少方法能够达到这个目的,下面一一介绍。jvm

3.1 WebApplicationInitializer接口

在Web应用程序中,经过WebApplicationInitializer能够对当前的ServletContext进行配置。

以下,经过注入spring.profiles.active变量能够为Spring上下文指定当前的 profile:

@Configuration
public class MyWebApplicationInitializer 
  implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
  
        servletContext.setInitParameter(
          "spring.profiles.active", "dev");
    }
}

3.2 经过 web.xml定义

与上面的方法相似,在web.xml中经过context-param元素也能够设置profile。

但前提是当前应用程序使用了xml的配置文件风格,以下:

<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>

3.3 JVM启动参数

经过Java程序启动参数一样能够对profile进行设定,以下:

java -jar application.jar -Dspring.profiles.active=dev

spring-boot-maven-plugin插件也支持设定profile,其原理也是经过启动参数实现,能够参考这里

https://docs.spring.io/spring-boot/docs/current/maven-plugin/examples/run-profiles.html

3.4 环境变量

在Unix/Linux环境中,能够经过环境变量注入profile的值:

export spring_profiles_active=dev
java -jar application.jar

3.5 application.properties

能够在application.properties配置文件中指定spring.profiles.active属性:

spring.profiles.active=dev

SpringBoot默认会加载并读取该配置,当发现为profile=dev时,会同时关联加载application-dev.properties这个配置。
这种方式很是简单,能够实现对不一样环境采用单独的配置文件进行隔离。

3.6 Maven Profile

Maven自己也提供了Profile的功能,能够经过Maven的Profile配置来指定Spring的Profile。

这种作法稍微有点复杂,须要先在pom.xml中设定不一样的 maven profile,以下:

<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>

这里,分别声明了dev和prod两个profile,每一个profile都包含了一个spring.profiles.active属性,这个属性用来注入到 Spring中的profile入参。
在SpringBoot的配置文件application.properties中,须要替换为这个maven传入的property:

## 使用Maven的属性进行替换
spring.profiles.active=@spring.profiles.active@

接下来,须要让Maven在打包时能将application.properties进行过滤处理,同时替换掉变量,需编辑pom.xml以下:

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

这里定义了filtering=true,所以Resource打包插件会对配置文件执行过滤。

若是你的项目pom定义继承自 spring-boot-starter-parent,那么能够不须要配置这个filter

最后,在maven打包时指定参数以下:

mvn clean package -Pprod

3.7 使用 @ActiveProfiles

@ActiveProfile 是用于单元测试场景的注解,能够为测试代码指定一个隔离的profile,以下:

@ActiveProfiles("test")
public void ApiTest{
  ...
}

3.8 使用 ConfigurableEnvironment

ConfigurableEnvironment 这个Bean封装了当前环境的配置信息,你能够在启动应用前进行设定操做:

SpringApplication application = new SpringApplication(MyApplication.class);

//设置environment中的profiler
ConfigurableEnvironment environment = new StandardEnvironment();
environment.setActiveProfiles("dev","join_dev");

application.setEnvironment(environment);
application.run(args)

3.9 SpringApplication.setAdditionalProfiles

SpringApplication这个类还提供了setAdditionalProfiles方法,用来让咱们实现"附加"式的profile。
这些profile会同时被启用,而不是替换原来的active profile,以下:

SpringApplication application = new SpringApplication(MyApplication.class);
application.setAdditionalProfiles("new_dev");

这种方式能够实现无条件的启用profile,优先级是最高的。
固然,还能够经过设定spring.profiles.include来达到一样的目的。

4、 优先级

至此,咱们已经提供了不少种方法来设定 Spring应用的profile,当它们同时存在时则会根据必定优先级来抉择,参考以下:

  1. SpringApplication.setAdditionalProfiles
  2. ConfigurableEnvironment、@ActiveProfiles
  3. Web.xml的 context-param
  4. WebApplicationInitializer
  5. JVM 启动参数
  6. 环境变量
  7. Maven profile、application.properties

从上至下,优先级从高到低排列。
其中,Maven profile与配置文件的方式相同,环境变量以及JVM启动参数会覆盖配置文件的内容。
1和2则属于进程内的控制逻辑,优先级更高。
若是在启动SpringBoot应用前对当前ConfigurableEnvironment对象注入了profile,则会优先使用这个参数, ActiveProfiles用于测试环境,其原理与此相似。
SpringApplication.setAdditionalProfiles则是不管如何都会附加的profile,优先级最高。

5、 案例

最后,咱们在SpringBoot中演示一个使用Profile的例子。

通常,在开发环境和生产环境中的数据源配置是不一样的,借助Profile咱们能够定义出不一样环境的数据源Bean。
首先咱们先建立一个接口:

public interface DatasourceConfig {
    public void setup();
}

对于开发环境,DatasourceConfig实现以下:

@Component
@Profile("dev")
public class DevDatasourceConfig implements DatasourceConfig {
    @Override
    public void setup() {
        System.out.println("Setting up datasource for DEV environment. ");
    }
}

一样,为生产环境也实现一个DatasourceConfig:

@Component
@Profile("production")
public class ProductionDatasourceConfig implements DatasourceConfig {
    @Override
    public void setup() {
       System.out.println("Setting up datasource for PRODUCTION environment. ");
    }
}

接下来,咱们声明一个Bean,对数据源执行初始化方法:

@Component
public class SpringProfilesTest {
    @Autowired
    DatasourceConfig datasourceConfig;
 
    @PostConstruct
    public void setupDatasource() {
        datasourceConfig.setup();
    }
}

以后,在application.properties的配置为:

spring.profiles.active=dev

启动SpringBoot 应用,发现输出以下:

Setting up datasource for DEV environment.

此时说明dev的profile被启用了!

参考文档

https://www.baeldung.com/spring-profiles
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
http://dolszewski.com/spring/spring-boot-properties-per-maven-profile/
https://www.concretepage.com/spring-5/activeprofiles-example-spring-test
https://docs.spring.io/spring-boot/docs/current/maven-plugin/examples/run-profiles.html

点击查看美码师的 SpringBoot 补习系列

相关文章
相关标签/搜索