一、简介

Profile的意思是配置,对于应用程序来说,不同的环境需要不同的配置。

比如:

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

Spring框架提供了多profile的管理功能,我们可以使用profile功能来区分不同环境的配置。

二、 区分Bean对象

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

通过@Profile注解可以为一个Bean赋予对应的profile名称,如下:

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

上面的DevDatasourceConfig被定义为 profile=dev,于是该Bean只会在dev(开发环境)模式下被启用。

如果需要定义为非dev环境,可以使用这样的形式:

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

XML风格配置

上面的例子也可以使用XML配置文件达到同样的目的,如下:

<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);
}
}
}

三、 设置Profile

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

有很多方法可以达到这个目的,下面一一介绍。

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来达到同样的目的。

四、 优先级

至此,我们已经提供了很多种方法来设定 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,优先级最高。

五、 案例

最后,我们在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 补习系列

补习系列(22)-全面解读 Spring Profile 的用法的更多相关文章

  1. 补习系列(17)-springboot mongodb 内嵌数据库

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  2. 补习系列(10)-springboot 之配置读取

    目录 简介 一.配置样例 二.如何注入配置 1. 缺省配置文件 2. 使用注解 3. 启动参数 还有.. 三.如何读取配置 @Value 注解 Environment 接口 @Configuratio ...

  3. 补习系列(6)- springboot 整合 shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  4. 补习系列(17)-springboot mongodb 内嵌数据库【华为云技术分享】

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  5. 补习系列(20)-大话 WebSocket 与 "尬聊"的实现

    目录 一.聊聊 WebSocket 二.Stomp 是个什么鬼 三.SpringBoot 整合 WebSocket A. 引入依赖 B. WebSocket 配置 C. 控制器 D. 前端实现 四.参 ...

  6. 补习系列(19)-springboot JPA + PostGreSQL

    目录 SpringBoot 整合 PostGreSQL 一.PostGreSQL简介 二.关于 SpringDataJPA 三.整合 PostGreSQL A. 依赖包 B. 配置文件 C. 模型定义 ...

  7. 补习系列(18)-springboot H2 迷你数据库

    目录 关于 H2 一.H2 用作本地数据库 1. 引入依赖: 2. 配置文件 3. 样例数据 二.H2 用于单元测试 1. 依赖包 2. 测试配置 3. 测试代码 小结 关于 H2 H2 数据库是一个 ...

  8. 补习系列(16)-springboot mongodb 数据库应用技巧

    目录 一.关于 MongoDB 二.Spring-Data-Mongo 三.整合 MongoDB CRUD A. 引入框架 B. 数据库配置 C. 数据模型 D. 数据操作 E. 自定义操作 四.高级 ...

  9. 补习系列(1)-springboot项目基础搭建课

    目录 前言 一.基础结构 二.添加代码 三.应用配置 四.日志配置 五.打包部署 小结 前言 springboot 最近火的不行,目前几乎已经是 spring 家族最耀眼的项目了.抛开微服务.技术社区 ...

随机推荐

  1. js 动态生成button 并设置click事件

    <div id="MyDiv"></div> <script> function AddButton() { var MyDiv =docume ...

  2. 【C/S通信交互之Http篇】Cocos2dx(Client)使用Curl与Jetty(Server)实现手机网游Http通信框架(内含解决curl.h头文件找不到问题)

    之前已经分享过一篇基于Cocos2dx与服务器使用Socket进行通信的框架,还不太熟悉的请移步到如下博文中: [C/S通信交互之Socket篇]Cocos2dx(Client)使用BSD Socke ...

  3. 读BeautifulSoup官方文档之html树的搜索(1)

    之前介绍了有关的四个对象以及他们的属性, 但是一般情况下要在杂乱的html中提取我们所需的tag(tag中包含的信息)是比较复杂的, 现在我们可以来看看到底有些什么搜索的方法. 最主要的两个方法当然是 ...

  4. LeetCode - 4 - Longest Substring Without Repeating Characters

    题目 URL:https://leetcode.com/problems/median-of-two-sorted-arrays/ 解法 二分法. 总的思想是将 2 个数组用 2 个指针“整体”二分. ...

  5. delphi中获取memo鼠标所在位置的行和列(通过EM_GETRECT消息取得Rect后,自己算一下)

    也是看别人写的,但是不容易找到,就转发一篇delphi版本的 function GetLine(X, Y: integer): TPoint;var  OldFont : HFont;  Hand : ...

  6. Android微信支付SDK

    App对接微信调起微信支付需要在微信平台注册,鉴别的标识就是App的包名,所以将申请的包名单独打包成一个Apk文件,则在其他的App调起此Apk的时候同样可以起到调用微信支付的功能.这样就实现了调起微 ...

  7. einsum:爱因斯坦求和约定

    在Tensorflow.Numpy和PyTorch中都提供了使用einsum的api,einsum是一种能够简洁表示点积.外积.转置.矩阵-向量乘法.矩阵-矩阵乘法等运算的领域特定语言.在Tensor ...

  8. MinGW 编译 libsndfile-1.0.25(只要有 MSYS,./configure make make install 就行了)

    最近做的一个项目需要读写 wav 文件.在网上找到 libsndfile 刚好满足我的需要.但是编译的时候遇到了点小麻烦,这里记录一下编译的过程,免得下次再编译时忘记了. 因为是在编译完成若干天后写的 ...

  9. Nginx 部署 Ant Design pro

    利用Ant Design pro开发的项目,如何用Nginx部署呢? 第一步:把项目打包,打包命令如下: npm run build 运行完毕会在项目目录下生成dist文件夹. 第二步:想要测试打包好 ...

  10. SharePoint Add-in Model (App Model) 介绍 – 概念、托管方式、开发语言

    SharePoint Add-in Model 是自 2013 版本以来引入的新的扩展性开发模型, SharePoint 开发者可以利用这种新模型来实现往常利用场解决方案 (Farm Solution ...