Maven高级

Maven高级

继承与聚合

继承

继承:即子工程可继承父工程的配置信息

  1. 定义一个父工程parent
  2. 定义创建许多子工程item,子工程共同用到的依赖 (如lombok)可定义在父工程中实现依赖传递。

定义父工程

如果一个工程为父工程,其打包方式必须设置为pom(默认为jar)。

pom.xml文件根标签中定义如下:

xml 复制代码
<packaging>pom</packaging>

常见的打包方式

  • jar:普通模块打包,内嵌tomcat运行
  • war:普通web程序打包,需要部署到外部tomcat服务器上运行
  • pom父工程聚合工程 ,该模块不写代码,仅进行依赖管理

定义子工程

在子工程的<parent>中声明父工程坐标信息

例:

xml 复制代码
<parent>
    <groupId>com.gezishan</groupId>
    <artifactId>item-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../item-parent/pom.xml</relativePath>
</parent>

Spring工程也用到了maven继承,所有SpringBoot创建的项目都继承了spring-boot-starter-parent工程:

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.5.6</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

这样,子工程就继承了父工程了,众多子工程公共用到的配置可以在父工程中声明(如依赖的版本)。

注:maven中一个工程只能继承一个父工程,即只能单继承 ,不能多继承

版本管理

父工程在pom.xml<dependencyManagement>统一声明依赖版本

xml 复制代码
<dependencyManagement>  <!-- 集中声明版本 -->
<dependencies>  <!-- 版本管理子项 -->
  <dependency>  <!-- 具体依赖坐标 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.0</version>  <!-- 统一版本 -->
  </dependency>
  <dependency>
    ...
  </dependency>
</dependencies>
</dependencyManagement>

注:<dependencyManagement>只是管理依赖版本,但不实际引入,具体引入是由子类工程决定的。

子工程引入依赖

xml 复制代码
<dependencies>  <!-- 版本管理子项 -->
  <dependency>  <!-- 具体依赖坐标 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!-- 无需指定版本 -->
  </dependency>
  <dependency>
    ...
  </dependency>
</dependencies>

统一还可以通过自定义属性的方法实现,这样要写的代码少一点。

自定义属性 :在<properties>中定义(一般在父工程中定义)

xml 复制代码
<properties>
    <lombok.version>1.28.24</lombok.version>
</properties>

引用属性 :在需要的插槽使用${}引用(一般在子工程中引用)

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>${lombok.version}</version>
</dependency>

聚合

聚合:将多个项目模块组织成一个整体(这样可以同时进行项目的构建与运行)。

如果有多个工程需要构建,一个一个工程进行构建,太麻烦了;可以利用聚合,将多个工程管理起来,实现一键构建安装。

聚合工程 :一个不具有业务代码的"空"工程,有且仅有一个pom.xml文件。

一般将父工程作为聚合工程,子工程作为被聚合的工程,将一个父工程进行安装,其他被聚合的(子)工程也同时进行安装。

实现

  1. 在父工程中定义<modules>标签设置当前工程所包含的子模块
xml 复制代码
<modules>
    <module>../pojo</module>  <!--填入模块地址-->
    <module>../utils</module>
    ...
</modules>

胖包与痩包

Maven对项目打包有两种方式胖包痩包胖包 包含所有依赖 jar 包可直接运行,瘦包仅含项目自身代码需依赖外部环境。

  • 胖包(Fat Jar/War):也叫 uber-jar,打包时会将项目代码、所有依赖的第三方 jar 包、配置文件全部整合到一个归档文件中。
  • 瘦包(Thin Jar/War):仅包含项目自身的编译代码和配置文件,不携带第三方依赖,依赖需从运行环境(如 Maven 仓库、服务器依赖目录)更据配置信息加载引用。

关键区别

  1. 体积与独立性:胖包体积大(几十 MB 到数百 MB),可独立运行无需额外依赖;瘦包体积小(几 MB 以内),运行需依赖外部依赖环境。
  2. 部署与维护:胖包部署简单,直接上传运行即可;瘦包需提前配置依赖环境,但更新项目时无需重复上传依赖,效率更高。
  3. 适用场景:胖包适合单机部署、快速测试、微服务独立实例;瘦包适合集群部署、容器化(如 Docker)、依赖共享的分布式环境。

Maven 打包实现方式

  • 胖包实现 :常用 maven-assembly-pluginspring-boot-maven-plugin(Spring Boot 项目),配置打包时包含依赖。
  • 瘦包实现 :使用默认的 maven-jar-pluginmaven-war-plugin,不额外配置依赖打包,仅输出项目自身代码。

具体实现

打包的方式其实各种各样,本质是通过打包的插件实现,也可以自己写插件自定义打包。

胖包(maven-assembly-plugin)

xml 复制代码
<plugin>  <!--maven官方胖包打包插件-->
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.5.5</version>  <!--插件版本-->
    <configuration>  
        <archive> 
            <manifest> 
                <mainClass>com.xxg.Main</mainClass>  
            </manifest>  
        </archive>  
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>  
        </descriptorRefs>  
    </configuration>  
</plugin>

核心配置

  1. <archive> :配置生成 Jar 包的元数据(如清单文件 MANIFEST.MF

  2. archive > manifest :配置清单文件MANIFEST.MF

  3. archive > manifest > mainClass :指定 Jar 包的主类,确保通过 java -jar 包名.jar 命令可直接运行

  4. <descriptorRefs>:引用插件内置的打包规则(描述符)

  5. descriptorRefs > descriptorRef:配置其中一条打包规则

  6. jar-with-dependencies:插件内置的关键规则,表示打包时会将:

    项目自身编译后的 .class 文件和所有依赖的第三方 Jar 包(包括 compileruntime 范围的依赖)全部合并到一个 Jar 包中,形成 "胖包"。

效果

配置后,执行 mvn assembly:assembly 命令会生成两个 Jar 包:

  1. 普通瘦包(仅项目自身代码,如 xxx-1.0-SNAPSHOT.jar)。
  2. 胖包(含所有依赖,如 xxx-1.0-SNAPSHOT-jar-with-dependencies.jar)。

胖包可直接通过 java -jar 胖包文件名.jar 运行,无需额外手动添加依赖。

胖包(spring-boot-maven-plugin)

SpringBoot项目打包最常用且最简单的方式是用SpringBoot的打包plugin

spring-boot-maven-pluginSpring Boot 官方提供的 Maven 插件,专为 Spring Boot项目设计,核心作用是将项目打包为可直接运行的 Spring Boot 专属胖包(Fat Jar/War) ,同时集成了 Spring Boot 特有的打包、运行、依赖管理等功能。

xml 复制代码
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

pom中加入此插件,再点击maven [install][repackge]就会把当前项目里所有依赖包和当前项目的源码都打成一个JAR包,同时还会将没有依赖包的JAR包也打出来。

核心特点

  1. 生成可直接运行的 Fat Jar

    打包后包含项目自身代码、所有第三方依赖(compileruntime 范围的依赖,自动处理依赖冲突)、Spring Boot 启动器(spring-boot-loader),无需额外配置依赖环境,直接通过 java -jar 包名.jar 运行。

  2. 特殊的 Jar 结构

    与普通胖包不同,其内部采用分层结构:

    • BOOT-INF/classes/:存放项目自身编译 后的 .class 文件和配置文件。

    • BOOT-INF/lib/:存放所有第三方依赖 Jar 包。

    • META-INF/:包含清单文件(MANIFEST.MF),已指定 Spring Boot 启动类

      org.springframework.boot.loader.JarLauncher)。这种结构由spring-boot-loader组件负责解析,支持嵌套 Jar 加载,解决了普通 Fat Jar 的类加载冲突问题。

  3. 内置项目运行功能

    支持通过 mvn spring-boot:run 命令直接启动项目,无需先打包,方便开发调试。

  4. 支持分层打包(Layered Jar)

    可将依赖、资源、应用代码等拆分为不同层,配合 Docker 构建时实现层缓存,加速镜像构建(Spring Boot 2.3+ 支持)。

痩包(maven-jar-plugin)

或者maven-war-plugin,这是Maven默认的打包方式,无需额外指定。直接打包,不打包依赖包,仅打包出项目中的代码到JAR包中。

设置lib目录

痩包通常需要借助外部的环境,常通过pom.xml配置 MANIFEST.MF 清单文件,指定类路径主类,方便运行时加载外部依赖。

xml 复制代码
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>com.yourpakagename.mainClassName</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

核心配置

  1. archive > manifest :配置 Jar 包的清单文件(MANIFEST.MF
  2. <addClasspath>true</addClasspath> :自动将项目的依赖 Jar 包名 添加到清单文件的 Class-Path 中。

​ 例如:若项目依赖 spring-core-5.3.0.jar,则 MANIFEST.MF 中会生成:Class-Path: ~spring-core-5.3.0.jar ...

~表示路径的前缀,可通过<classpathPrefix>配置。

  1. <classpathPrefix>lib/</classpathPrefix> :指定依赖 Jar 包的存放路径前缀。

    结合上一条,生成的 Class-Path 会自动加上 lib/ 前缀,即运行环境中,依赖需放在与当前 Jar 包同级的 lib 目录下。

    (若不配置,默认依赖需与 Jar 包放在同一目录,配置后更便于依赖管理)。

  2. mainClass>com.yourpakagename.mainClassName</mainClass :指定 Jar 包的主类(包含 main 方法的类),确保可以通过 java -jar 包名.jar 直接运行。

​ 例如:com.example.App 表示主类全路径,会在 MANIFEST.MF 中生成:Main-Class: com.example.App

效果

配置后,执行 mvn package 会生成一个瘦包 (仅含项目自身的 .class 和配置文件),同时 MANIFEST.MF 中会包含:

复制代码
Main-Class: com.yourpakagename.mainClassName
Class-Path: lib/xxx1.jar lib/xxx2.jar ...
依赖复制

上述痩包的打包,必须手动提供依赖 (否则运行时会报 ClassNotFoundException)。可以配合 maven-dependency-plugin 自动将依赖复制到 lib 目录。

xml 复制代码
<plugins>
  <!-- 生成瘦包并配置清单 -->
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <classpathPrefix>lib/</classpathPrefix>
          <mainClass>com.yourpakagename.mainClassName</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

  <!-- 添加插件,自动将依赖复制到 target/lib 目录 -->
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>copy-dependencies</id>  <!--指定执行单元唯一标识,方便日志查看-->
        <phase>package</phase>  <!--绑定到那个生命周期执行,绑定后可自动执行-->
        <goals>
          <goal>copy-dependencies</goal>  <!--指定当前执行单元要运行的插件目标(goal)为复制依赖-->
        </goals>
        <configuration>
          <outputDirectory>${project.build.directory}/lib</outputDirectory> <!-- 依赖输出目录 -->
        </configuration>
      </execution>
    </executions>
  </plugin>
</plugins>

<!--
${project.build.directory}是 Maven 内置的预定义属性,其值指向项目构建的输出目录,默认路径为:项目根目录/target。
-->

执行 mvn package 后,target 目录会生成:

  • 瘦包(如 xxx-1.0.jar

  • lib目录(包含所有依赖 Jar 包)

    此时可直接通过 java -jar xxx-1.0.jar运行(依赖已在 lib目录中,符合清单文件配置)。

相关推荐
lkbhua莱克瓦242 小时前
Java基础——常用算法4
java·数据结构·笔记·算法·github·排序算法·快速排序
.格子衫.2 小时前
Maven前奏
java·pycharm·maven
Mos_x2 小时前
springboot系列--自动配置原理
java·后端
神奇侠20242 小时前
基于spring-boot-admin实现对应用、数据库、nginx等监控
java·数据库·nginx
一叶飘零_sweeeet3 小时前
手写 RPC 框架
java·网络·网络协议·rpc
脸大是真的好~4 小时前
黑马JAVAWeb-01 Maven依赖管理-生命周期-单元测试
java·maven
zhangkaixuan4565 小时前
Apache Paimon 查询全流程深度分析
java·apache·paimon
cici158746 小时前
MyBatis注解的运用于条件搜索实践
java·tomcat·mybatis
wangqiaowq6 小时前
StarRocks安装部署测试
java·开发语言