# Maven 进阶
# 参考文档
# 配置文件
# 继承与聚合
虽然在开发的时候,会将继承和聚合一起使用,但是这是两个完全不同的概念。
# 继承
继承就是子模块自动继承父模块的一些依赖、插件、属性等。
继承的目的是为了消除重复性,实际项目中最常用的就是将子模块 POM 中很多相同的配置提取出来统一锁定在父模块 POM 中。如 groupId
、artifactId
、version
等。然后在使用的时候,子模块会继承到父模块的版本号,子模块不需要再指定版本号,方便统一管理项目依赖。
可以继承到的资源有:
继承使用的元素是 <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>
2
3
4
5
6
7
8
9
通过 IDEA 可以看到 maven 中包含了 spring-boot-maven-plugin
插件:
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 进行查看,如下图:
# 打包后结构
配置了 spring-boot-maven-plugin
插件后,执行 mvn clean install
命令后,会在 target 目录下生成打包后的信息:
打包后会有两个 jar 信息,一个是 mvn install
原始打包生成的 jar 包,一个是 spring-boot-maven-plugin
repackage 之后生成的可执行 jar 包。
# 可执行 jar
可执行 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 的内部结构:
可以看到通过 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
2
3
4
5
其中没有包含 Start-Class
、Main-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>
2
3
4
5
- 配置的
classifier
表示可执行 jar 的名字,配置了这个之后,在插件执行repackage
命令时,就不会给mvn package
所打成的 jar 重命名了,这样就可以被其他项目引用了,classifier
命名的为可执行 jar。
这样原始 jar 就可以正常被引用当前包下的内容了。
# 私服
# 讨论区
由于评论过多会影响页面最下方的导航,故将评论区做默认折叠处理。