项目中一直应用Maven的profile特性解决不同环境的部署问题。最近在尝试解决本地调试环境的时候碰到一些问题,顺便仔细研究了一下。因为项目仍然在用普通SpringMVC架构,没有切换到Spring Boot,所以例子以SpringMVC为基础。

这里就不介绍Profile的基础知识了,不了解的请找相关资料查一下。

1    Profile的基础使用

我们常见的两种使用Profile的方法:占位符替换和文件复制。

1.1 Profile定义

在项目的pom.xml中定义不同的profile,以数据库主机地址为例。

<profiles>

<profile>

<id>dev</id>

<properties>

<active.profile>dev</active.profile>

<database.host>localhost</database.host>

</properties>

</profile>

<profile>

<id>test</id>

<properties>

<active.profile>test</active.profile>

<database.host>test.codestory.tech</database.host>

</properties>

</profile>

<profile>

<id>prod</id>

<properties>

<active.profile>prod</active.profile>

<database.host>prod.codestory.tech</database.host>

</properties>

</profile>

</profiles>

1.2 替换占位符方法

为了简化,将本位涉及的所有参数保存到 src/main/resources/config下的props.properties 文件中,格式为

database.pool.host=${database.host}

在pom.xml中定义 resources 插件,定制资源复制的动作。

<build>

<resources>

<resource>

<directory>src/main/resources</directory>

<filtering>true</filtering><!-- 替换占位符 -->

</resource>

</resources>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-resources-plugin</artifactId>

<version>3.0.2</version>

<configuration>

<encoding>UTF-8</encoding>

<overwrite>true</overwrite><!-- 目标文件存在时覆盖 -->

</configuration>

</plugin>

</plugins>

</build>

执行 maven 命令,指定 profile 复制资源,复制的资源在目录 target/classes 下。分别用三个不同的profile执行mvn 命令后结果如下:

mvn clean resources:resources -P dev

database.pool.host=localhost

mvn clean resources:resources -P test

database.pool.host=test.codestory.tech

mvn clean resources:resources -P prod

database.pool.host=prod.codestory.tech

1.3 复制文件方法

除了使用properties替换占位符的方法,还可以分别为每个profile编写文件,打包时根据选择的profile进行复制。

创建各个profile需要的配置文件,在src/main/resources 中创建目录 profiles ,并在其中创建三个子目录:dev/test/prod,每个子目录中创建一个props.properties文件,内容分别为

src/main/resources/profiles/dev/props.properties

database.pool.host=localhost

src/main/resources/profiles/test/props.properties

database.pool.host=test.codestory.tech

src/main/resources/profiles/prod/props.properties

database.pool.host=prod.codestory.tech

为了测试resources-plugin的参数 overwrite ,我们将 src/main/resources/config/props.properties 内容增加一行,变为

database.pool.host=${database.host}

database.pool.port=3306

在pom.xml中修改resources部分配置

<resources>

<resource>

<directory>src/main/resources</directory>

<excludes>

<exclude>profiles/**</exclude>

</excludes>

<filtering>true</filtering><!-- 替换占位符 -->

</resource>

<resource>

<directory>src/main/resources/profiles/${active.profile}</directory>

<targetPath>config</targetPath>

<filtering>false</filtering><!-- 不替换占位符,直接复制 -->

</resource>

</resources>

同样执行maven resources命令后查看文件内容,

mvn clean resources:resources -P dev

database.pool.host=localhost

注意属性文件中没有 database.pool.port=3306 这一行,说明是复制文件的结果,而不是直接替换占位符。

2    同时使用多个profile

前面的例子足够简单,也能解决大部分场景下打包的问题。扩展一下场景,看看问题如何解决?

2.1 本地用test环境调试

为了场景需要,假设props.properties文件中还有一个参数,用于记录附件的保存路径(为了场景假设的,使用分布式文件服务器或webdav等技术的同学请忽视)。

database.pool.host=${database.host}

filesystem.path.root=${path.root}

现在测试同学在测试环境发现了BUG,开发需要访问test环境数据库进行联调,但附件保存路径不同,本地不能直接使用 -P test。使用Tomcat远程调试的同学也请绕道一下。另外还有一个简单的办法,修改一下pom.xml中的profile[test]中path.root参数即可解决。不过为了研究profile,也不用这个太简单的方案。

2.2 多个profile 替换占位符的方法

解决的思路是保持原有的profile配置信息不变,额外选中一个本地调试用的profile,替换其中少量参数。

pom.xml中profiles内容修改为

<profiles>

<profile>

<id>local</id>

<properties>

<active.profile>local</active.profile>

<path.root>d:/develop/attachments</path.root>

</properties>

</profile>

<profile>

<id>dev</id>

<properties>

<active.profile>dev</active.profile>

<database.host>localhost</database.host>

<path.root>d:/develop/attachments</path.root>

</properties>

</profile>

<profile>

<id>test</id>

<properties>

<active.profile>test</active.profile>

<database.host>test.codestory.tech</database.host>

<path.root>/app/attachments</path.root>

</properties>

</profile>

<profile>

<id>prod</id>

<properties>

<active.profile>prod</active.profile>

<database.host>prod.codestory.tech</database.host>

<path.root>/app/attachments</path.root>

</properties>

</profile>

</profiles>

使用多个profile,在-P参数后,只需要用逗号分隔即可。我的目的是用local中的参数替换test中同名参数,所以将 local放在后面。(需要在pom.xml中注释掉<directory>src/main/resources/profiles/${active.profile}</directory>这个resource定义)

mvn clean resources:resources -P test,local

database.pool.host=test.codestory.tech

filesystem.path.root=/app/attachments

发现文件内容并没有按照我预期的目标替换,而是仍然用了test的参数。在网上搜索,在百度知道一个回答中找到了答案 https://zhidao.baidu.com/question/139071460381210925.html ,【它是根据profile定义的先后顺序来进行覆盖取值的,然后后面定义的会覆盖前面定义的。】

因此,修改 pom.xml中profiles的顺序,将local放到最后,重新执行命令

mvn clean resources:resources -P test,local

database.pool.host=test.codestory.tech

filesystem.path.root= d:/develop/attachments

2.3 多个profile复制文件

再来试试复制文件的方法是否继续有效。为了测试方便,在profiles/{active.profile}的目录下,分别放置了一个不同的属性文件,文件名含profile名,分别为env-dev.properties/env-test.properties /env-prod.properties。

首先,只用一个profile测试

mvn clean resources:resources -P test

在target/classes/config 目录中可以看到两个文件 env-test.properties和props.properties,说明复制文件成功;查看文件内容,可以发现都是从 src/main/resources/profiles/test 目录复制而来。

测试两个profile,再检查目录 target/classes/config,发现只有一个文件 props.properties,并且内容是 src/main/resource/config/props.properties文件替换占位符的结果。

mvn clean resources:resources -P test,local

database.pool.host=test.codestory.tech

filesystem.path.root=d:/develop/attachments

为了测试原因,在 src/main/resource/config/props.properties 中增加一个参数activeProfiles,文件内容为:

database.pool.host=${database.host}

filesystem.path.root=${path.root}

active.profiles=${active.profile}

mvn clean resources:resources -P test,local

database.pool.host=test.codestory.tech

filesystem.path.root=d:/develop/attachments

active.profiles=local

原因在于:根据优先级,参数active.profile只保留了最后一个 local,所以无法实现拷贝 test 目录下文件的效果。

2.4 修改profile复制文件方法

在maven的pom规范中,在每个profile中还可以定义build参数,因此将pom.xml中profiles部分内容修改为

<profiles>

<profile>

<id>dev</id>

<properties>

<active.profile>dev</active.profile>

<database.host>localhost</database.host>

<path.root>d:/develop/attachments</path.root>

</properties>

    <build>

      <resources>

        <resource>

          <directory>src/main/resources/profiles/dev</directory>

          <targetPath>config</targetPath>

          <filtering>false</filtering>

        </resource>

      </resources>

    </build>

</profile>

<profile>

<id>test</id>

<properties>

<active.profile>test</active.profile>

<database.host>test.codestory.tech</database.host>

<path.root>/app/attachments</path.root>

</properties>

<build>

<resources>

<resource>

<directory>src/main/resources/profiles/test</directory>

<targetPath>config</targetPath>

<filtering>false</filtering>

</resource>

</resources>

</build>

</profile>

<profile>

<id>prod</id>

<properties>

<active.profile>prod</active.profile>

<database.host>prod.codestory.tech</database.host>

<path.root>/app/attachments</path.root>

</properties>

<build>

<resources>

<resource>

<directory>src/main/resources/profiles/prod</directory>

<targetPath>config</targetPath>

<filtering>false</filtering>

</resource>

</resources>

</build>

</profile>

<profile>

<id>local</id>

<properties>

<active.profile>local</active.profile>

<path.root>d:/develop/attachments</path.root>

</properties>

</profile>

</profiles>

可以看到,在每个profile中增加了文件复制的内容。同之前配置的区别在于:不再使用变量 ${active.profile},而是直接写profile的名称。删除之前定义的<directory>src/main/resources/profiles/${active.profile}</directory>,再次测试

mvn clean resources:resources -P test,local

在target/classes/config 目录中可以看到两个文件 env-test.properties和props.properties,说明复制文件成功。

当然这时候想达到本节开始的场景:本地使用test数据库调试,需要拆分props.properties为两个文件,分别处理了:数据库信息放一个文件(使用复制文件的方法),文件目录放另一个文件(使用替换占位符的方法)。

3    尝试在项目配置文件中记录所使用的Profiles

前面的例子中,使用active.profiles=${active.profile}记录的值,只有最后一个profile的id。如果想记录所有使用到的profile,希望配置文件中的值是active.profiles=test,local。该怎么做呢?

经过测试,发现maven有一个内置参数是 activeProfiles。将原始配置文件修改为 active.profiles=${activeProfiles}

mvn clean resources:resources -P test,local

active.profiles=[Profile {id: test, source: pom}, Profile {id: local, source: pom}]

在网上搜索了很久,没发现用什么办法能够处理${activeProfiles}的输出值。不过文本也足够简单,可以在项目中读出这个字符串后进行后续处理,比如处理为: active.profiles=test,local

4    在Maven的settings.xml中定义profile

除了项目pom.xml中定义profile,还可以在maven/conf/settings.xml中定义。为了测试profile的优先级,定义了两个profile,并且新加了一个属性active.profile.label,并且将local和test的顺序互换。

<profiles>

<profile>

<id>local</id>

<properties>

<active.profile>local</active.profile>

<active.profile.label>settings profile local</active.profile.label>

<filesystem.path.root>d:/develop/attachments</filesystem.path.root>

</properties>

</profile>

<profile>

<id>test</id>

<properties>

<active.profile>test</active.profile>

<active.profile.label>settings profile test</active.profile.label>

</properties>

</profile>

</profiles>

创建一个profiles.txt文件用于输出,原始内容(为了区别输出内容,增加了#字符分隔行)

###############################################

active.profiles=${activeProfiles}

###############################################

active.profile.label=${active.profile.label}

###############################################

使用命令

mvn clean resources:resources -P test,local

###############################################

active.profiles=[Profile {id: test, source: pom}, Profile {id: local, source: pom}, Profile {id: local, source: settings.xml}, Profile {id: test, source: settings.xml}]

###############################################

active.profile.label=settings profile test

###############################################

由此可见,当同时在pom.xml和settins.xml中定义了相同id的profile,其加载顺序是先依次加载 pom.xml中的Profiles,再加载settings.xml中的profiles。当定义了相同名称的属性时,很可能会导致意外的结果。

灵活使用Maven Profile的更多相关文章

  1. 项目实现不同环境不同配置文件-maven profile

    最近接触的项目都是在很多地方都落地的项目,需要支持不同的环境使用不同的配置文件.一直以来都以为是人工的去写不同的配置文件,手动的去修改运用的配置文件.感觉自己还是太low呀.maven的使用的还停留在 ...

  2. 使用maven profile实现多环境可移植构建(转自CSDN)

    使用maven profile实现多环境可移植构建 标签: maven profilemaven自动构建maven自动部署maven可移植构建持续集成 2014-04-25 23:37 26905人阅 ...

  3. 通过maven profile 打包指定环境配置

    背景 最近换了个新公司接手了一个老项目,然后比较坑的是这个公司的项目都没有没有做多环境打包配置,每次发布一个环境都要手动的去修改配置文件.今天正好有空就来配置下. 解决这个问题的方式有很多,我这里挑选 ...

  4. maven profile实现多环境配置

    每次项目部署上线都需要手动去修改配置文件(比如数据库配置,或者一个自定义的配置)然后才能打包,很麻烦,网上找到 maven profile可以完成这个工作,记录如下: 环境:eclipse + spr ...

  5. 在eclipse激活maven profile配置

    profile简介 profile可以让我们定义一系列的配置信息,然后指定其激活条件.这样我们就可以定义多个profile,然后每个profile对应不同的激活条件和配置信息,从而达到不同环境使用不同 ...

  6. CAS (13) —— CAS 使用Maven Profile支持多环境编译

    CAS (13) -- CAS 使用Maven Profile支持多环境编译 摘要 CAS 使用Maven Profile支持多环境编译 版本 tomcat版本: tomcat-8.0.29 jdk版 ...

  7. maven profile 优先级

    maven profile是有优先级别 也就是说在setting.xml的profile优先级比pom中同名的profile高. 可以使用 mvn help:active-profiles 这个命令是 ...

  8. How to activate maven profile inside eclipse

    How to activate maven profile inside eclipse Normally maven is use for project dependency management ...

  9. 记录一次诡异的Maven Profile不生效的问题

    记录一次诡异的Maven Profile不生效的问题 现象 maven 打包之后,复制的 profile对应的resource文件总是不正确的. 即便是加了 mvn clean package -P ...

随机推荐

  1. java反射机制获取自定义注解值和方法

    由于工作需求要应用到java反射机制,就做了一下功能demo想到这些就做了一下记录 这个demo目的是实现动态获取到定时器的方法好注解名称,废话不多说了直接上源码 1.首先需要自定义注解类 /** * ...

  2. 利用Shell开发MySQL的启动脚本

    MySQL实例部署情况 01:MySQL程序安装目录:/data/apps/mysql 02:MySQL实例3306的配置文件为:/data/mysql/3306/my.cnf 03:MySQL实例3 ...

  3. 什么是BFC? CSS 如何使用伪元素清除浮动?

    .BFC概念: 块级格式化上下文,是一个独立的渲染区域,让处于 BFC 内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响. 我们先了解一个名词:BFC(block formatting c ...

  4. ES6 新增声明变量的 var let const 的区别详解

    var 如果使用关键字 var 声明一个变量,那么这个变量就属于当前的函数作用域,如果声明是发生在任何函数外的顶层声明,那么这个变量就属于全局作用域. let 1.let 声明的变量具有块作用域的特征 ...

  5. 关于vue中使用rem问题

    1.下载lib-flexible 我使用的是vue-cli+webpack,所以是通过npm来安装的 npm i lib-flexible --save 2.引入lib-flexible 在main. ...

  6. 最方便分布式爬虫管理框架--Gerapy

    Gerapy 是一款国人开发的爬虫管理软件(有中文界面) 是一个管理爬虫项目的可视化工具,把项目部署到管理的操作全部变为交互式,实现批量部署,更方便控制.管理.实时查看结果. gerapy和scrap ...

  7. Go - Slice 切片

    概述 切片是一种动态数组,比数组操作灵活,长度不是固定的,可以进行追加和删除. len() 和 cap() 返回结果可相同和不同. 声明切片 //demo_7.go package main impo ...

  8. 关于Keepalive的那些事

    服务端很多同学包括自己对keepalive理解不清晰,经常搞不清楚,TCP也有keepalive,HTTP也有keepalive,高可用也叫keepalive,经常混淆这几个概念.做下这几个概念的简述 ...

  9. ServiceFabric极简文档-1.3删除群集

    删除群集 若要删除群集,请运行包文件夹中的 RemoveServiceFabricCluster.ps1 Powershell 脚本,并传入 JSON 配置文件的路径. 可以选择性地指定删除日志的位置 ...

  10. Java EE核心框架实战(1)

    内容前言:本书适合具有一定Java编程基础的读者阅读,增强其项目实战能力. 2014年9月第1版 下载本书所有源代码可通过  http://pan.baidu.com/s/1i3sshXr 本书配套的 ...