# Maven 进阶

# 参考文档

# 配置文件

Maven 配置文件官方文档 (opens new window)

# 继承与聚合

虽然在开发的时候,会将继承和聚合一起使用,但是这是两个完全不同的概念。

# 继承

继承就是子模块自动继承父模块的一些依赖、插件、属性等。

继承的目的是为了消除重复性,实际项目中最常用的就是将子模块 POM 中很多相同的配置提取出来统一锁定在父模块 POM 中。如 groupIdartifactIdversion 等。然后在使用的时候,子模块会继承到父模块的版本号,子模块不需要再指定版本号,方便统一管理项目依赖。

可以继承到的资源有:

可以继承到的资源

继承使用的元素是 <parent>,子模块必须指定父模块。父模块坐标中的 <packaging> 必须是 pom,否则子模块不会继承。

父模块中实现依赖管理的元素是 <dependencyManagement>

  • <dependencyManagement> 只是声明依赖,不会引入,只有子模块中的 <dependency> 中指定后,才会解析依赖。

注意:<dependencyManagement> 中的版本号会覆盖所有的传递依赖的版本号!!

# 聚合

聚合就是将多个模块统一进行打包,他们是整体与部分的关系。聚合就是在执行 maven 命令构建项目时,整个项目会被打包在一起。

聚合使用的元素是 <module>,注意 <module> 中的是相对路径,被聚合的顺序也不是声明的顺序(实际是按照依赖关系来执行的)。

简单讲就是执行总模块的 compile,那就会执行所有被聚合的 compile

# 跳过测试

命令后添加参数 -D skipTests,例如 mvn install -D skipTests

# 打包 package

# Spring boot 打包插件

以常用的 spring boot 举例,spring boot 工程创建好之后,会发现 pom.xml 最下面默认配置了一个打包插件,如果是手动创建的 maven 项目就要手动添加这个插件了。

<build>
    <plugins>
        <plugin>
            <!-- 该插件会将 jar 运行所有需要的依赖 jar 打包进去 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
1
2
3
4
5
6
7
8
9

通过 IDEA 可以看到 maven 中包含了 spring-boot-maven-plugin 插件:

IDEA 中插件视图

Goal 功能说明:

  • build-info:生成项目的构建信息文件 build-info.properties
  • repackage:这个是 默认 goal,在 mvn package 执行之后,这个命令再次打包生成可执行的 jar,同时将 mvn package 生成的 jar 重命名为 *.origin
  • run:这个可以用来运行 Spring Boot 应用。
  • start:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理。
  • stop:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理。

spring-boot-maven-plugin 插件默认在父工程 sprint-boot-starter-parent 中被指定为 repackage,如果需要设置其他属性,需要在当前应用的pom中进行设置。可以点击sprint-boot-starter-parent 进入父 pom 进行查看,如下图:

Springboot maven plugin 的默认值

# 打包后结构

配置了 spring-boot-maven-plugin 插件后,执行 mvn clean install 命令后,会在 target 目录下生成打包后的信息:

打包后 target 目录信息

打包后会有两个 jar 信息,一个是 mvn install 原始打包生成的 jar 包,一个是 spring-boot-maven-plugin repackage 之后生成的可执行 jar 包。

# 可执行 jar

可执行 jar 的内部结构:

repackage 得到的可执行 jar

  • 其中 BOOT-INF 主要是一些启动信息,包含 classes 和 lib 文件,classes 文件放的是项目里生成的字节文件 class 和配置文件,lib 文件是项目所需要的 jar 依赖。

  • META-INF 目录下主要是 maven 的一些元数据信息,MANIFEST.MF 文件内容如下:

    Manifest-Version: 1.0
    Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
    Implementation-Title: play
    Implementation-Version: 1.0-SNAPSHOT
    Spring-Boot-Layers-Index: BOOT-INF/layers.idx
    // Start-Class 是项目的主程序入口,即 main 方法。
    Start-Class: cn.test.controller.PlayApp
    // Springboot-Boot-Classes 和 Spring-Boot-Lib 指向的是生成的 BOOT-INF 下的对应位置。
    Spring-Boot-Classes: BOOT-INF/classes/
    Spring-Boot-Lib: BOOT-INF/lib/
    Build-Jdk-Spec: 1.8
    Spring-Boot-Version: 2.4.5
    Created-By: Maven Jar Plugin 3.2.0
    Main-Class: org.springframework.boot.loader.JarLauncher
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    • 其中 Main-Class 属性值为 org.springframework.boot.loader.JarLauncher,这个值可以通过设置属性 layout 来控制:

      <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <configuration>
              <!--使用 -Dloader.path 需要在打包的时候增加 <layout>ZIP</layout>,不指定的话 -Dloader.path 不生效-->
              <layout>ZIP</layout>
              <!-- 指定该jar包启动时的主类[建议],即启动类 -->
              <mainClass>cn.test.controller.PlayApp</mainClass>
          </configuration>
          <executions>
              <execution>
                  <goals>
                      <goal>repackage</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17

打包出来的可执行 jar 之所以可以使用 java -jar 运行,和 MANIFEST.MF 文件里的配置关系密切。

# Original jar

原始 jar 的内部结构:

原始 jar

可以看到通过 mvn package 构建的 jar 是一个普通的 jar,包含的都是项目的字节文件和一些配置文件,没有将项目依赖的第三方 jar 包含进来。再看下 MANIFEST.MF 文件:

Manifest-Version: 1.0
Implementation-Title: play
Implementation-Version: 1.0-SNAPSHOT
Build-Jdk-Spec: 1.8
Created-By: Maven Jar Plugin 3.2.0
1
2
3
4
5

其中没有包含 Start-ClassMain-Class 等信息,这个与可执行 jar 的该文件存在很多差异,而且目录结构也有很大差异。

# 可执行 jar 的一些问题

一般对使用 spring-boot-maven-plugin 插件打出的可执行 jar 不建议作为 jar 给其他服务引用。

因为可能出现访问可执行 jar 中的一些配置文件找不到的问题。如果想让构建出来的原始 jar 不被重新打包,可以对 spring-boot-maven-plugin 插件配置 classifier 属性,自定义一个可运行 jar 名称,这样该插件就不会对原始的 jar 重命名操作了。

<configuration>
    <!-- 指定该 jar 包启动时的主类[建议],即启动类 -->
    <mainClass>cn.test.controller.PlayApp</mainClass>
    <classifier>repackageCanExec</classifier>
</configuration>
1
2
3
4
5
  • 配置的 classifier 表示可执行 jar 的名字,配置了这个之后,在插件执行 repackage 命令时,就不会给 mvn package 所打成的 jar 重命名了,这样就可以被其他项目引用了,classifier 命名的为可执行 jar。

重命名后 jar 结构

这样原始 jar 就可以正常被引用当前包下的内容了。

# 私服

# 讨论区

由于评论过多会影响页面最下方的导航,故将评论区做默认折叠处理。

点击查看评论区内容,渴望您的宝贵建议~
Last Updated: 2/23/2023, 5:07:18 PM