侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 285 篇文章
  • 累计创建 125 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

maven中profiles使用详解,与Filtering结合使用实战

孔子说JAVA
2022-05-16 / 0 评论 / 0 点赞 / 162 阅读 / 14,527 字 / 正在检测是否收录...

在实际生产中,每个项目都会有多套运行环境(开发,测试,正式等等),不同的环境配置也不尽相同(如jdbc.url),springboot中提供了 spring.profile.active 的方式来实现多环境的切换,通过设置环境变量和启动参数的方式终究不能一劳永逸,要么需要修改yml文件,要么需要记得启动的时候带上参数。而利用maven的profiles 可以减少很多工作。让我们通过几个例子一步步的掌握使用maven的profiles属性。

1、Profile 简介

什么是profile? <profile> 就像 <dependencies> 一样是pom文件里的一个xml元素,在profile里几乎可以定义所有在pom里的定义的内容(<dependencies><properties>,插件配置等等,不过不能再定义他自己了)。当一个profile被激活时,它定义的<dependencies><properties>等就会覆盖掉原pom里定义的相同内容,从而可以通过激活不同的profile来使用不同的配置。

<!-- profile 的感性认识 -->
<project>
    ...
    <profiles>
      <profile>
        <id>dev</id>
        <properties>
            <active.profile>dev</active.profile>
            <pom.jdbc.url>jdbc:mysql://127.0.0.1:3306/dev</pom.jdbc.url>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>3.2.4.RELEASE</version>
            </dependency>
        <dependencies>
      </profile>
    </profiles>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
    </dependencies>
    ...
</project>

2、Profile 如何配置和激活

2.1 Profile如何配置

可以在 pom.xmlsettings.xml 中配置profile,如果profile被激活,profile里的配置和原pom的配置会做覆盖合并。

  • pom.xml里可以定义的配置:<repositories>、<pluginRepositories>、<dependencies>、<plugins>、<properties>、<modules>、<reporting>、<dependencyManagement>、<distributionManagement> 以及build下的 <defaultGoal>、<resources>、<testResources>、<finalName>,在pom文件中配置的profile对当前模块有效。
  • 在maven的安装目录下的conf/settings.xml,其中配置的profile是全局的,对本机所有的maven项目有效,在里面定义的配置项也稍微少了些,只能定义远程服务器的信息和属性信息(<repositories>,<pluginRepositories>, <properties>)。这些信息在pom.xml里也是可以定义的。
  • 用户settings.xml:在用户目录下有一个.m2/settings.xml,其中配置的profile对当前用户的maven项目有效。
  • profiles.xml: 这是maven2中的配置方式,在maven3中已废弃。

后三种profile的配置方式,maven均不建议。

2.2 Profile的激活

可以通过多种方式激活profile(显式的,隐式的)

2.2.1 显式的激活

通过 maven 的 -P 参数激活指定的profile,参数的值是profile的id,多个profile以逗号分割,如果不想激活某个默认的profile,就在它的id前加个!

mvn -U clean package -Ptest,local,!ignore

IDEA里则可以在 Maven Projects 里直接勾选想要激活的profile

image-1652259597453

2.2.2 隐式的激活

配置profile时,可以在 <profile><activation> 元素下配置隐式激活的信息。

pom.xml文件配置默认激活

<!-- 默认激活 -->
<profiles>
  <profile>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
  </profile>
</profiles>

settings.xml文件配置默认激活

settings.xml文件通过 <activeProfiles> 来配置默认激活的profile列表

<activeProfiles>
   <activeProfile>artifactory</activeProfile>
</activeProfiles>

根据操作系统类型激活

  • 关于OS值的更多信息可以参考这里
<profiles>
    <profile>
        <activation>
            <os>
                <!-- 不必指定所有信息 -->
                <name>linux</name>
                <family>unix</family>
                <arch>amd64</arch>
                <version>3.19.0-30-generic</version>
            </os>
      </activation>
    </profile>
</profiles>

根据JDK版本激活

<!-- 如果jdk的版本为1.8则激活该profile -->
<profiles>
  <profile>
    <activation>
      <jdk>1.8</jdk>
    </activation>
    </profile>
</profiles>

也可以通过[1.6,1.8)匹配多个jdk版本,关于匹配模式的详细信息可以参考这里

根据环境变量激活

<!-- 如果环境变量里有`debug`且它的值为`true`则激活 -->
<!-- 也可以不指定`<value>`元素, 则只有环境变量里有`debug`就激活 -->
<profiles>
  <profile>
    <activation>
      <property>
        <name>debug</name>
        <value>true</value>
      </property>
    </activation>
  </profile>
</profiles>

执行命令:

mvn -U clean package -Ddebug=true

通过判断文件是否存在激活

<profiles>
  <profile>
    <activation>
      <file>
        <missing>/path/to/missing/file</missing>
        <exists>/path/to/exists/file</exists>
      </file>
    </activation>
    ...
  </profile>
</profiles>

不同类型的隐式激活方式可以组合使用,如同时指定根据操作系统类型和JDK版本来激活profile,那么只有两个条件都匹配是才能激活。

3、Profile 上手实战

3.1 profile 配置

pom.xml文件设置

<profiles>
  <profile>
    <!-- 不同环境Profile的唯一id -->
    <id>dev</id>
    <properties>
      <!-- profiles.active是自定义的字段(名字随便起),自定义字段可以有多个 -->
      <profiles.active>dev</profiles.active>
    </properties>
  </profile>
  <profile>
    <id>prod</id>
    <properties>
      <profiles.active>prod</profiles.active>
    </properties>
    <activation>
      <!-- 默认激活 -->
      <activeByDefault>true</activeByDefault>
    </activation>
  </profile>
  <profile>
    <id>test</id>
    <properties>
      <profiles.active>test</profiles.active>
    </properties>
  </profile>
</profiles>

目录结构

image-1652257928493

application.yml配置

spring:
  profiles:
    active: @profiles.active@

application-dev.yml中代码如下

server:
  port: 7091
  • 其他几个文件我只是把端口号进行了修改,方便打包看不同的效果。

3.2 maven打包与激活profiles

3.2.1 命令行方式

执行命令如下:

mvn clean package -Ptest

然后启动jar包,可以看到jar包启动的是test的配置,如果换成-Pdev启动的就是dev包的端口。

默认启动方式

如果不带-Ptest,启动的是 prod 的端口。因为在profiles中我们看到有配置默认的选项如下。

<activation>
  <activeByDefault>true</activeByDefault>
</activation>

3.2.2 通过IDEA的可视化的方式

如果使用IDEA工具进行开发,还可以使用可视化的方式进行打包,在Profiles下方选中需要激活的配置。

image-1652258045032

4、Profiles 高级用法

4.1 通过和pom结合的方式设置动态参数

如果我们希望通过docker-maven-plugin插件,把编译好的jar打包成docker并且传入相应的开发、测试、生产的服务器中去。这个时候,我们就需要根据不同的条件去传入不同的服务器。

在profiles中我们可以做以下定义

<profiles>
  <profile>
    <id>dev</id>
    <properties>
      <profile.id>dev</profile.id>
      <docker.host>http://dev.demo.com:2375</docker.host>
    </properties>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
  </profile>
  <profile>
    <id>test</id>
    <properties>
      <profile.id>test</profile.id>
      <docker.host>http://test.demo.com375</docker.host>
    </properties>
  </profile>
  <profile>
    <id>prod</id>
    <properties>
      <profile.id>prod</profile.id>
      <docker.host>http://prod.demo.com:2375</docker.host>
    </properties>
  </profile>
</profiles>

在pom文件的build控件中我们使用以下配置

<build>
  <plugins>
     <plugin>
       <groupId>com.spotify</groupId>
       <artifactId>docker-maven-plugin</artifactId>
       <version>1.1.0</version>
       <executions>
         <execution>
           <id>build-image</id>
           <phase>package</phase>
           <goals>
             <goal>build</goal>
           </goals>
         </execution>
       </executions>
       <configuration>
         <imageName>demo/${project.artifactId}</imageName>
         <imageTags>
           <imageTag>${project.version}-${current.time}</imageTag>
           <imageTag>latest</imageTag>
         </imageTags>
         <forceTags>true</forceTags>
         <dockerHost>${docker.host}</dockerHost>
         <forceTags>true</forceTags>
         <baseImage>java:8</baseImage>
         <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
         <resources>
           <resource>
             <targetPath>/</targetPath>
             <directory>${project.build.directory}</directory>
             <include>${project.build.finalName}.jar</include>
           </resource>
         </resources>
       </configuration>
     </plugin>
  </plugins>
</build>

其中 ${project.artifactId}${project.version} 是项目的 artifactId 和 version,${current.time} 是在build-helper-maven-plugin定义的。

${docker.host}则是我们在profiles中定义的,可以随着我们选择不同的profile,把jar包build成不同的docker镜像,并传入指定服务器。

4.2 通过和yml结合设置动态参数

除了可以在pom中设置动态参数,使得其根据profile的不同选择不同的参数。还可以通过设置不同的profile,让yml选择不同的参数。具体如下:

设置profiles

<profiles>
  <profile>
    <id>dev</id>
    <properties>
      <profile.id>dev</profile.id>
      <eureka.url>http://127.0.0.1:8001/eureka</eureka.url>
    </properties>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
  </profile>
  <profile>
    <id>test</id>
    <properties>
      <profile.id>test</profile.id>
      <eureka.url>http://base-registry:8001/eureka</eureka.url>
    </properties>
  </profile>
  <profile>
    <id>prod</id>
    <properties>
      <profile.id>prod</profile.id>
      <eureka.url>http://base-registry:8001/eureka</eureka.url>
    </properties>
  </profile>
  <profile>
    <id>new</id>
    <properties>
      <profile.id>new</profile.id>
      <eureka.url>http://base-registry:8001/eureka</eureka.url>
    </properties>
  </profile>
</profiles>

我们在profile中设置了一个eureka.url的属性,就可以在yml中直接调用。

eureka:
  client:
    service-url:
      defaultZone: @eureka.url@
    registry-fetch-interval-seconds: 10
  instance:
    prefer-ip-address: true

在IDEA调试和启动的时候,一般会报错如下:

org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token
found character ‘@’ that cannot start any token.

解决方法就是引入 yaml.sankeyaml的jar包

<dependency>
  <groupId>org.yaml</groupId>
  <artifactId>snakeyaml</artifactId>
</dependency>

4.3 打包不同的资源

在profile打包yml文件的时候,如果我们解压了jar包,会发现还是把所有的application-profile.yml文件给打包进去了。这个可以通过设置打包参数,只打包需要的application文件。

<profiles>
  <profile>
    <id>dev</id>
    <properties>
      <env>dev</env>
    </properties>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
  </profile>
  <profile>
    <id>prd</id>
    <properties>
      <env>prd</env>
    </properties>
  </profile>
</profiles>

<build>
  <finalName>springmvc</finalName>
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>*.xml</include>
      </includes>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
      <excludes>
        <exclude>dev/*</exclude>
        <exclude>prd/*</exclude>
      </excludes>
    </resource>
    <resource>
      <directory>src/main/resources/${env}</directory>
    </resource>
  </resources>
</build>

目录结构如下:

image-1652258196023

4.4 Filtering + Profile

思路:在不同的profile里配置不同的属性(properties),然后激活相应的profile,用其中的属性去替换jdbc.properties里的占位符。

  • Filtering 是 maven 的 resource 插件 提供的功能,作用是用环境变量、pom文件里定义的属性和指定配置文件里的属性替换属性(*.properties)文件里的占位符(${jdbc.url})。

4.4.1 Filtering简单示例

在src/main/resources目录有个配置文件jdbc.properties,内容如下:

jdbc.url=${pom.jdbc.url}
jdbc.username=${pom.jdbc.username}
jdbc.passworkd=${pom.jdbc.password}

配置 resource 插件,启用filtering功能并添加属性到pom:

<project>
    ...
    <!-- 用pom里定义的属性做替换 -->    
    <properties>
        <pom.jdbc.url>jdbc:mysql://127.0.0.1:3306/dev</pom.jdbc.url>
        <pom.jdbc.username>root</pom.jdbc.username>
        <pom.jdbc.password>123456</pom.jdbc.password>
    </properties>
    <build>
      ...
        <!-- 可以把属性写到文件里,用属性文件里定义的属性做替换
        <filters>
            <filter>src/main/filters.properties</filter>
        </filters> -->
        <resources>
          <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
          </resource>
        </resources>
        ...
    </build>
    ...
</project>

编译包后target目录下的jdbc.properties:

jdbc.url=jdbc:mysql://127.0.0.1:3306/dev
jdbc.username=root
jdbc.passworkd=123456

4.4.2 Filtering + Profile 示例

继续使用上述例子,现在添加三个profile配置,分别对应开发,测试,正式环境。修改后的pom文件如下:

<project>
...
<build>
    <filters>
        <filter>src/main/filters-${active.profile}.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
                <filtering>true</filtering>
        </resource>
    </resources>
</build>
<profiles>
    <profile>
        <id>dev</id>
        <properties>
            <active.profile>dev</active.profile>
        </properties>
        <!-- 把当前profile设置为默认profile,可以同时这是多个为默认-->
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <id>test</id>
        <properties>
            <active.profile>test</active.profile>
        </properties>
    </profile>
    <profile>
        <id>product</id>
        <properties>
            <active.profile>product</active.profile>
        </properties>
    </profile>
</profiles>
...
</project>

然后在src/main下新建三个文件:filters-dev.properties, filters-test.properties, filters-product.properties ,文件内容如下(以filters-dev.properties为例):

pom.jdbc.url=jdbc:mysql://127.0.0.1:3306/dev
pom.jdbc.username=root
pom.jdbc.password=123456

用 dev profile 打开发包, mvn clean package -Pdev, 打包后jdbc.properties文件内容如下:

jdbc.url=jdbc:mysql://127.0.0.1:3306/dev
jdbc.username=root
jdbc.password=123456

4.4.3 maven-antrun-plugin插件 + Profile 示例

如果不同的运行环境只是属性值的不同,用 profile + filtering 进行变量的替换可以很好的满足打包需求,如果不是简单的替换(如log4j.xml,开发环境只要输出到标准输出,测试和线上环境则还需要输出到文件且文件的位置和策略也不相同),这个就需要借助 maven 的 ant 插件(maven-antrun-plugin)。src/main/resources目录下有三个log4j的配置文件,分别对应三个运行环境:

resources
├── log4j-product.xml
├── log4j-test.xml
└── log4j.xml

配置如下profile:

<profiles>
  <profile>
    <id>dev</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <build>
      <resources>
        <resource>
          <directory>src/main/resources</directory>
          <excludes>
            <exclude>config.*.properties</exclude>
            <exclude>log4j-*.xml</exclude>
          </excludes>
        </resource>
      </resources>
    </build>
  </profile>
  <profile>
    <id>test</id>
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <executions>
            <execution>
              <phase>test</phase>
              <goals>
                <goal>run</goal>
              </goals>
              <configuration>
                <tasks>
                  <delete file="${project.build.outputDirectory}/log4j.xml"/>
                  <delete file="${project.build.outputDirectory}/log4j-product.xml"/>
                  <move file="${project.build.outputDirectory}/log4j-test.xml"
                                              tofile="${project.build.outputDirectory}/log4j.xml"/>
                </tasks>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
  <profile>
    <id>product</id>
    <properties>
      <active.profile>product</active.profile>
    </properties>
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <executions>
            <execution>
              <phase>test</phase>
              <goals>
                <goal>run</goal>
              </goals>
              <configuration>
                <tasks>
                  <delete file="${project.build.outputDirectory}/log4j.xml"/>
                  <delete file="${project.build.outputDirectory}/log4j-test.xml"/>
                  <move file="${project.build.outputDirectory}/log4j-product.xml"
                                              tofile="${project.build.outputDirectory}/log4j.xml"/>
                </tasks>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>
0

评论区