maven中profile使用详解
1. profile语法
- 项目在不同环境,比如开发环境、测试环境、生产环境,有的配置可能会不一样,比如数据源配置、日志文件配置、以及一些软件运行过程中的基本配置
- 每次我们部署到不同环境时, 都需要修改相应的配置文件,这样来回修改,很容易出错,而且浪费劳动力
- 而maven也提供了一种灵活的解决方案,也就是profile功能
1.1 profile中的配置结构
基本囊括所有pom中可以定义的元素, 根据不同profile, 生效的元素不一样
<project>
<profiles>
<profile>
<build>
<defaultGoal>...</defaultGoal>
<finalName>...</finalName>
<resources>...</resources>
<testResources>...</testResources>
<plugins>...</plugins>
</build>
<reporting>...</reporting>
<modules>...</modules>
<dependencies>...</dependencies>
<dependencyManagement>...</dependencyManagement>
<distributionManagement>...</distributionManagement>
<repositories>...</repositories>
<pluginRepositories>...</pluginRepositories>
<properties>...</properties>
</profile>
</profiles>
</project>
1.2 profile的定义位置
我们可以有多个地方定义profile。定义的地方不同,它的作用范围也不同。
- 针对于特定项目的profile配置我们可以定义在该项目的pom.xml中。
- 针对于特定用户的profile配置,我们可以在用户的settings.xml文件中定义profile。该文件在用户家目录下的“.m2”目录下。
- 全局的profile配置。全局的profile是定义在Maven安装目录下的“conf/settings.xml”文件中的。
其中profile中能够定义的配置信息, 跟profile所处的位置是相关的。
以下就分两种情况来讨论,一种是定义在settings.xml中,另一种是定义在pom.xml中。
- profile定义在settings.xml中
当profile定义在settings.xml中时意味着该profile是全局的,它会对所有项目或者某一用户的所有项目都产生作用。因为它是全局的,所以在settings.xml中只能定义一些相对而言范围宽泛一点的配置信息,比如远程仓库等。而一些比较细致一点的需要根据项目的不同来定义的就需要定义在项目的pom.xml中。具体而言,能够定义在settings.xml中的信息有<repositories>、<pluginRepositories>和<properties>
。定义在<properties>
里面的键值对可以在pom.xml中使用。
- profile定义在pom.xml中
定义在pom.xml中的profile可以定义更多的信息。主要有以下这些:
<repositories>
<pluginRepositories>
<dependencies>
<plugins>
<properties>
<dependencyManagement>
<distributionManagement>
还有build元素下面的子元素,主要包括:
<defaultGoal>
<resources>
<testResources>
<finalName>
1.3 如何激活profile
- profile定义中使用activeByDefault默认激活
<profiles>
<profile>
<id>profileTest1</id>
<properties>
<hello>world</hello>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>profileTest2</id>
<properties>
<hello>andy</hello>
</properties>
</profile>
</profiles>
activeByDefault为true的时候就表示当没有指定其他profile为激活状态时,该profile就默认会被激活。所以当我们调用mvn package的时候上面的profileTest1将会被激活,但是当我们使用mvn package –P profileTest2的时候将激活profileTest2,而这个时候profileTest1将不会被激活
- 在settings.xml中使用activeProfiles指定激活的profile
<profiles>
<profile>
<id>profileTest1</id>
<properties>
<hello>world</hello>
</properties>
</profile>
<profile>
<id>profileTest2</id>
<properties>
<hello>andy</hello>
</properties>
</profile>
</profiles>
这里的profile可以是定义在settings.xml中的,也可以是定义在pom.xml中的。这个时候如果我们需要指定profileTest1为激活状态,那么我们就可以在settings.xml中定义activeProfiles,具体定义如下:
<activeProfiles>
<activeProfile>profileTest1</activeProfile>
</activeProfiles>
考虑这样一种情况,我们在activeProfiles下同时定义了多个需要激活的profile。这里还拿上面的profile定义来举例,我们定义了同时激活profileTest1和profileTest2。
<activeProfiles>
<activeProfile>profileTest1</activeProfile>
<activeProfile>profileTest2</activeProfile>
</activeProfiles>
从profileTest1和profileTest2我们可以看出它们共同定义了属性hello。那么这个时候我在pom.xml中使用属性hello的时候,它到底取的哪个值呢?是根据activeProfile定义的顺序,后面的覆盖前面的吗?根据我的测试,答案是非也,它是根据profile定义的先后顺序来进行覆盖取值的,然后后面定义的会覆盖前面定义的。
- 使用-P参数显示的激活一个profile
我们在进行Maven操作时就可以使用-P参数显示的指定当前激活的是哪一个profile了。比如我们需要在对项目进行打包的时候使用id为profileTest1的profile,我们就可以这样做 (P后面可以有空格也可以没有
):
mvn package –P profileTest1
当我们使用activeByDefault或settings.xml中定义了处于激活的profile,但是当我们在进行某些操作的时候又不想它处于激活状态,这个时候我们可以这样做:
Mvn package –P !profileTest1
这里假设profileTest1是在settings.xml中使用activeProfile标记的处于激活状态的profile,那么当我们使用-P !profile
的时候就表示在当前作中该profile将不处于激活状态。
1.4 查看当前处于激活状态的profile
我们可以同时定义多个profile,那么在建立项目的过程中,到底激活的是哪一个profile呢?Maven为我们提供了一个指令可以查看当前处于激活状态的profile都有哪些,这个指定就是mvn help:active-profiles
。
这里有个误区要特别注意: 同时激活的profile可以是多个, 它们可能是不同维度的. 如某个profile是用来管理repository的, 某个profile是管理某些properties的.
2. 具体使用场景
2.1 根据环境打包配置文件
- 项目结构
test-profile
├── pom.xml
├── src
│ ├── main
│ │ ├── config
│ │ │ ├── dev
│ │ │ │ └── redis.properties
│ │ │ ├── fat
│ │ │ │ └── redis.properties
│ │ │ ├── prd
│ │ │ │ └── redis.properties
│ │ │ └── uat
│ │ │ └── redis.properties
│ │ ├── java
│ │ └── resources
│ │ ├── dev
│ │ │ └── jdbc.properties
│ │ ├── fat
│ │ │ └── jdbc.properties
│ │ ├── prd
│ │ │ └── jdbc.properties
│ │ └── uat
│ │ └── jdbc.properties
│ └── test
├── target
- pom中配置profile
示例如下:
profile的id代表不同的环境, 每个profile定义了不同变量值
打包时根据变量值选择打包目录
<build>
<finalName>test-profile</finalName>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>src/main/config/${running.env}</directory>
<targetPath>WEB-INF/classes</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<running.env>dev</running.env>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<running.env>fat</running.env>
</properties>
</profile>
<profile>
<id>pp</id>
<properties>
<running.env>uat</running.env>
</properties>
</profile>
<profile>
<id>product</id>
<properties>
<running.env>prd</running.env>
</properties>
</profile>
</profiles>
- 打包
运行mvn clean package
(默认profile) 或 mvn clean package -Ptest
(指定profie) 打包后, 结构如下:
resource的目录全部打包到class目录中, config目录根据profile配置只有一个目录下的文件打包到class目录中
test-profile
├── META-INF
└── WEB-INF
└── classes
├── dev
│ └── jdbc.properties
├── fat
│ └── jdbc.properties
├── prd
│ └── jdbc.properties
├── redis.properties
└── uat
└── jdbc.properties
2.2 resources目录中选择目录打包
上述中的config目录未在resource打包默认的目录中, 所以会根据profile根据配置进行选择.
如果需要在resource打包默认的目录src/main/resouces下, 根据不同profile选择不同目录的配置. 则需要结合resource插件一起使用.
- pom中结合resources一起使用
pom中增加resource, 先把需要选择的所有目录排除掉, 再根据profile选择目录
<build>
<finalName>test-profile</finalName>
<resources>
<resource>
<directory>src/main/resources/</directory>
<!--打包时先排除掉三个文件夹-->
<excludes>
<exclude>dev/*</exclude>
<exclude>fat/*</exclude>
<exclude>prd/*</exclude>
<exclude>uat/*</exclude>
</excludes>
<includes>
<!--如果有其他定义通用文件,需要包含进来-->
<!--<include>messages/*</include>-->
</includes>
</resource>
<resource>
<!--这里是关键! 根据不同的环境,把对应文件夹里的配置文件打包-->
<directory>src/main/resources/${running.env}</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>src/main/config/${running.env}</directory>
<targetPath>WEB-INF/classes</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<running.env>dev</running.env>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<running.env>fat</running.env>
</properties>
</profile>
<profile>
<id>pp</id>
<properties>
<running.env>uat</running.env>
</properties>
</profile>
<profile>
<id>product</id>
<properties>
<running.env>prd</running.env>
</properties>
</profile>
</profiles>
- 打包
项目结构不变, 运行mvn clean package
(默认profile) 或 mvn clean package -Ptest
(指定profie) 打包后, 结构如下:
target/test-profile
├── META-INF
└── WEB-INF
└── classes
├── jdbc.properties
└── redis.properties