maven-resources-plugin详解

发布时间 2023-08-02 15:59:15作者: 红尘过客2022

核心资料来源:

maven-resources-plugin详解 (csdn.net)

  • maven-resources-plugin到低在什么场景下使用?
  • 他到底有什么作用?
  • 他和pom当中配置的resources标签又有什么关联?
  • 为什么有的项目使用了该插件而有的却没有?
  • resources当中的filtering标签到低是干什么的?
  • maven怎么打包过滤文件?

一、什么场景会用到?

这个插件只要我们编译代码就会用到该插件,就算我们项目没有声明该插件也照样会使用到,怎么证明呢?

我们可以在一个新的maven项目,不添加任何依赖,然后使用mvn clean install

可以看到启动时调用了插件:maven-resources-plugin:3.2.0

PS D:\workspace\java\SpringBootWebTest> mvn clean install
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for com.wht.test:SpringBootWebTest:jar:1.0-SNAPSHOT
[WARNING] 'build.plugins.plugin.(groupId:artifactId)' must be unique but found duplicate declaration of plugin org.apache.maven.plugins:maven-dependency-plugin @ line 136, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] -------------------< com.wht.test:SpringBootWebTest >-------------------
[INFO] Building SpringBootWebTest 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) @ SpringBootWebTest ---
[INFO] Deleting D:\workspace\java\SpringBootWebTest\target
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ SpringBootWebTest ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 0 resource
[INFO] Copying 0 resource
[INFO] Copying 2 resources to D:\workspace\java\SpringBootWebTest\target/config

Maven 默认为一些核心的生命周期阶段绑定了插件目标,当用户调用这些阶段时,对应的插件目标就会自动执行相应的任务。

其中maven-resources-plugin的resources和testResources两个目标,绑定到了default生命周期的process-resources和process-test-resources两个阶段上。

生命周期后续有空统一收集,暂时做下记录:

生命周期 阶段 插件目标 执行的任务
clean pre-clean
clean clean maven-clean-plugin:clean 清理Maven的输出目录
clean post-clean
site pre-site
site site maven-site-plugin:site 生成项目站点
site post-site
site site-deploy maven-site-plugin:deploy 部署项目站点
process-resources maven-resources-plugin:resources 复制资源文件到输出目录
complie maven-compiler-plugin:complie 编译代码到输出目录
process-test-resources maven-resources-plugin:testResources 复制测试资源文件到测试输出目录
default test-complie maven-compiler-plugin:testComplie 编译测试代码到测试输出目录
test maven-surefire-plugin:test 执行测试用例
package maven-jar-plugin:jar/maven-jar-plugin:war 创建项目jar/war包
install maven-install-plugin:install 将项目输出的包文件安装到本地仓库
deploy maven-deploy-plugin:deploy 将项目输出的包文件部署到远程仓库

二、他有什么作用?

他的作用是将项目的资源(resources目录下)目录的文件复制到输出目录(target),

输出目录又分为了两个:

一个是测试的输出目录,

一个是主资源的。

所以对应了process-resources和process-test-resources两个阶段上,当然一般测试目录并没有资源目录。

什么是资源文件?

.java文件在运行的时候需要通过JRE编译成.class文件,然后放到target目录,

然后本地启动项目的时候,jvm运行target目录下的编译过后的.class代码文件,

而资源文件就是不属于.java文件,

那也就意味着不需要参与编译工作,但是运行的时候又依赖与他。

这时候就需要通过maven-resources-plugin插件将其放到编译后的路径。

这样我们项目启动的时候资源文件才能被使用。

这也就是我们有时候项目经常会出现明明代码当中有这个文件,但是运行却说找不到文件的原因。

三、插件常用配置

1、字符集编码

既然插件是copy资源文件那必然涉及到文件的编码,可以选择的编码有ASCII, UTF-8 或者 UTF-16,设置编码的方式有两种

第一种:使用properties标签声明project.build.sourceEncoding,声明好后,插件当中的<encoding>标签会取这个编码

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

第二种通过插件配置:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.3.1</version>
        <configuration>
          ...
          <encoding>UTF-8</encoding>
          ...
        </configuration>
      </plugin>
    </plugins>
    ...
  </build>
  ...
</project>

注意:只要官网当中提到了可以使用${…}的方式配置,那么我们就可以不声明插件,可以直接在properties当中配置。

2.1、resources配置结构

resources标签其实就是maven-resources-plugin的配置,主要用来配置资源目录的

<build>
	<resources>
	  <resource>
	 		<directory>${project.basedir}/src/main/resources</directory>
	 		<filtering></filtering>
		  <includes>
	  			<include></include>
	 		</includes>
	  	<excludes>
	   			<exclude></exclude>
	  	</excludes>
	 </resource>
	  <!--假如资源目录有多个可以在这里声明-->
	  <resource>
	    ...
	  </resource>
	  
	</resources>
</build>
  • 标签<directory>指定资源文件目录
  • 标签 <includes>指定资源文件目录中,仅包含哪些文件被打包
  • 标签<excludes>指定资源文件目录中,仅哪些文件不被打包
  • 标签<filtering>是一个bool值,默认值为false。指定打包时的配置文件中是否进行变量替换

filtering我们经常会用两类配置,就是因为有些文件中的变量不能被替换,例如jsk,认证文件,xml等等,不需要替换变量的。

kafka引入认证,经常报错的就是没有filtering设置为false。

2.2、resources默认配置

所谓默认配置就是在项目当中不设置resources标签,他默认生效的

2.2.1、maven超级pom默认配置

maven项目默认继承了一个父pom.xml,配置主要包含了如下,其中一些配置就是对maven-resources-plugin插件的配置:

  <build>
    <directory>${project.basedir}/target</directory>
    <!-- 主资源默认输出的位置 -->
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <!--打出来的默认jar、war包名-->
    <finalName>${project.artifactId}-${project.version}</finalName>
    <!-- 测试资源默认输出的位置 -->
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <!--默认的主源代码地址-->
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
    <!--默认的测试源代码地址-->
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <!--默认的主源代码当中的资源文件地址-->
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <!--默认的测试源代码当中的资源文件地址-->
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
  </build>
2.2.2、spring-boot对resources插件的默认配置

springboot项目一般我们都会继承一个spring-boot-starter-parent,而他的pom当中就默认给我们做了一些resources插件的配置:

像这些resources标签的都是resources插件的配置,关于这个配置起到了什么作用后面会讲!

 <resources>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <filtering>true</filtering>
        <includes>
          <include>**/application*.yml</include>
          <include>**/application*.yaml</include>
          <include>**/application*.properties</include>
        </includes>
      </resource>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <excludes>
          <exclude>**/application*.yml</exclude>
          <exclude>**/application*.yaml</exclude>
          <exclude>**/application*.properties</exclude>
        </excludes>
      </resource>
    </resources>

除此之外pluginManagement当中还存在resources插件的配置,如下:

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-resources-plugin</artifactId>
          <configuration>
            <propertiesEncoding>${project.build.sourceEncoding}</propertiesEncoding>
            <delimiters>
              <delimiter>${resource.delimiter}</delimiter>
            </delimiters>
            <useDefaultDelimiters>false</useDefaultDelimiters>
          </configuration>
        </plugin>
2.2.3、resources最终生效的配置

假如我们项目没有继承spring-boot-starter-parent那么我们的项目默认继承了一个父pom,resources默认配置如下:

<resources>
  <resource>
    <directory>${project.basedir}/src/main/resources</directory>
  </resource>
</resources>

假如继承了spring-boot-starter-parent,那么我们的的项目resources默认配置如下,他会将maven默认配置给替换掉:

<resources>
  <resource>
    <directory>${basedir}/src/main/resources</directory>
    <filtering>true</filtering>
    <includes>
      <include>**/application*.yml</include>
      <include>**/application*.yaml</include>
      <include>**/application*.properties</include>
    </includes>
  </resource>
  <resource>
    <directory>${basedir}/src/main/resources</directory>
    <excludes>
      <exclude>**/application*.yml</exclude>
      <exclude>**/application*.yaml</exclude>
      <exclude>**/application*.properties</exclude>
    </excludes>
  </resource>
</resources>

这里需要注意一点:假如我们项目当中去声明resources标签,那么他会将继承的父类当中的resources标签给替换掉,说白了就是重写的会覆盖继承的

2.3、resources下的标签详解

2.3.1、filtering的使用

关于这个标签官网也有叙述:https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html

filtering默认为false,作用是是否允许指定任意文件可以以${...} or @...@的语法来提取pom.xml当中的配置。

用法示例:

1.资源文件中使用${keyword}占位符来定义变量, 如src/main/resouces/application.properties:

spring.profiles.active=@active.profile@
server.servlet.context-path=/test
test=@project.build.sourceEncoding@
test2=${project.build.sourceEncoding}

2.这时候可以在pom.xml文件中定义变量的取值

3.如果需要对配置文件中变量进行替换实际值,就需要开启<filtering>,该值设置为true。

这里使用了includes标签指定了文件,也就是允许application.properties文件读取变量值。

            <resource>
                <directory>config</directory>
                <filtering>true</filtering>
                <includes>
                    <include>application.properties</include>
                </includes>
                <targetPath>${project.build.directory}/config</targetPath>
            </resource>
            <resource>
                <directory>config</directory>
                <filtering>false</filtering>
                <includes>
                    <include>application-${profies.active}.properties</include>
                    <include>client.truststore.jks</include>
                </includes>
                <targetPath>${project.build.directory}/config</targetPath>
            </resource>

4.执行mvn clean package 打包,然后打开target/classes目录当中查看资源文件,会发现使用 @...@取值成功了,而${...} 没有成功。

原因:这是因为我这个项目继承了spring-boot-starter-parent,而springboot的xml当中有一个这个标签<resource.delimiter>将取值语法改为了 @...@,因为spring害怕和其他语法有冲突,所以使用了这个配置。

         <properties>
    <java.version>1.8</java.version>
    <resource.delimiter>@</resource.delimiter>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  </properties>
       
       <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-resources-plugin</artifactId>
          <configuration>
            <propertiesEncoding>${project.build.sourceEncoding}</propertiesEncoding>
            <delimiters>
              <delimiter>${resource.delimiter}</delimiter>
            </delimiters>
            <useDefaultDelimiters>false</useDefaultDelimiters>
          </configuration>
        </plugin>

我们也可以通过手动声明来覆盖springboot父类的配置,这样便可以通过${...}语法进行取值了。

<properties>
	<resource.delimiter>${*}</resource.delimiter>
</properties>

5.通过命令进行指定变量的值:mvn clean package -DskipTests -Dusername="lisi"

注:命令的优先级要高于pom当中配置的变量值

6.另, 变量的定义可以不放在pom里, 也可以指定其他文件, 通过build.filters.filter配置即可. 示例:

<build>
	<filters>
		<filter>src\main\resources\filters_file.properties</filter>
	</filters>
	<resources>
		<resource>
			<directory>src/main/resources</directory>
			<filtering>true</filtering>
            <includes>
                <include>application.properties</include>
            </includes>
        </resource>
	</resources>
</build>
2.3.2、为什么非得使用includes指定文件?

没有必要使用变量取值的,千万不要将filtering设置为true,

针对于这一点官网也明确指出二进制文件一定不要过滤

之前我遇到过一个bug就是resources文件夹当中存放有Excel模板,

导出模板后发现是乱码的,但是通过源代码打开Excel就是正常的,原因就是将文件给进行过滤了。

导致编译过后target当中的Excel都是乱码的。

2.3.3、include和excludes的使用

关于这个标签官网也有叙述:https://maven.apache.org/plugins/maven-resources-plugin/examples/include-exclude.html

我们来看springboot默认的配置,针对于上面一个环节我们已经搞清楚了,但是下面的呢,为什么允许了,后面又使用exclude给过滤掉了呢?

其实实际开发当中很多人对这都是不理解,配置起来也是一顿乱配置。多读两遍我图片上写的注释,一旦理解了,就彻底懂了!

include和excludes标签也可以同时出现在一个resource当中,例如如下:
将以txt结尾的文件copy到target,需要排除掉文件名当中携带test的。

**/代表的是根目录,/src/main/resources 和 /src/main/java 这两个都属于根目录,一个*可以代表一个占位符,可以是多个字母组成的

<build>
  ...
  <resources>
    <resource>
      <directory>src/my-resources</directory>
      <includes>
        <include>**/*.txt</include>
      </includes>
      <excludes>
        <exclude>**/*test*.*</exclude>
      </excludes>
    </resource>
    ...
  </resources>
  ...
</build>

2.4、什么场景需要配置resources?

  1. 假如src/main/java下存在非.java文件,但是也需要参与打包,这时候需要手动配置resources,因为不管是maven默认继承的父pom还是springboot的父pom,都只会将resources下的资源文件参与打包。
  2. 如果项目继承了spring-boot-starter-parent,然后需要使用application.properties变量取值,是可以不配置的,因为springboot默认配置了,假如我们还有很多配置文件,例如application-dev.properties、application-prod.properties这些都需要使用变量取值,这时候就需要覆盖掉springboot的resources配置来手动配置。
  3. 有的项目会习惯性将每个版本的升级sql存放到resources文件夹下,假如我们不做任何配置的情况下,他也会参与打包。假如sql文件比较大,那打出来的jar包也一定很大。
  4. 默认的资源目录就是src/main/resources,假如项目有资源目录以外的文件需要参与打包这时候就需要手动指定。

关于resources标签当时我还专门写了一篇关于这个的文章,当时其实是似懂非懂,只能说通过亲自试验得出来了一些结论:https://blog.csdn.net/weixin_43888891/article/details/122406081

两篇文章结合着看基本上就可以彻底掌握了!