乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 介绍与核心概念

    • Maven是什么
    • 约定优于配置
  • 第2章 安装与配置

    • 安装与验证
    • settings.xml
    • 本地仓库与镜像
  • 第3章 POM与项目坐标

    • POM
    • GAV坐标
    • packaging
  • 第4章 标准目录布局

    • 标准目录布局
  • 第5章 依赖机制

    • dependencies
    • scope
    • 依赖传递
    • 依赖冲突与调解
    • exclusions
    • optional
    • dependencyManagement
  • 第6章 仓库

    • 仓库体系
    • 本地仓库
    • 远程仓库与镜像
    • 私服
  • 第7章 构建生命周期

    • 生命周期概述
    • clean 生命周期
    • default 生命周期
    • site 生命周期
    • 生命周期与插件绑定
  • 第8章 插件

    • 插件概述
    • maven-compiler-plugin
    • maven-surefire-plugin
    • maven-war-plugin
  • 第9章 继承与聚合

    • parent继承
    • 聚合
    • BOM
    • properties
  • 第10章 属性与资源过滤

    • 资源过滤
    • Profile
  • 第11章 常用命令

    • mvn compile
    • mvn test
    • mvn package
    • mvn clean
    • mvn install
    • mvn dependency:tree
  • 第12章 常见问题与最佳实践

    • 依赖冲突排查
    • 最佳实践

mvn package

本章承接 mvn test,进入 default 生命周期的打包阶段。理解 mvn package 的作用和产物生成机制,是掌握 Maven 构建"最终交付物"的关键——JAR/WAR 就是项目的可运行产物。


核心机制

package 阶段将编译后的代码打包为可分发格式,如 JAR(Java Archive,普通 Java 项目)或 WAR(Web Application Archive,Web 项目)。

注意这里的"可分发格式"——package 的产物是可以脱离源码、独立部署的文件。JAR 可以直接用 java -jar 运行(如果是可执行 JAR),WAR 可以直接丢进 Tomcat 部署。

package 阶段在生命周期中的位置

default 生命周期的相关阶段链:

... → compile → test-compile → test → package → verify → install → deploy

执行 mvn package 时,Maven 会自动依次执行从 validate 到 package 的所有前置阶段。也就是说,mvn package 隐式包含了 compile 和 test。

谁在做真正的打包工作?

打包工作由与 <packaging> 类型对应的插件完成:

packaging 类型默认绑定的插件产物
jarmaven-jar-plugin.jar 文件
warmaven-war-plugin.war 文件
pom无无(多模块项目的父项目)
maven-pluginmaven-plugin-pluginMaven 插件包

默认情况下,普通 Java 项目的 <packaging> 是 jar,因此 mvn package 会调用 maven-jar-plugin 将 target/classes/ 中的内容打包为 JAR。

JAR 包里有什么?

一个标准的 Maven JAR 包内部结构:

employee-system-1.0.0.jar
├── META-INF/
│   ├── MANIFEST.MF          ← 清单文件(包含版本、主类等信息)
│   └── maven/               ← Maven 元数据
│       └── com.feixiang/
│           └── employee-system/
│               ├── pom.xml
│               └── pom.properties
└── com/feixiang/            ← 编译后的 .class 文件
    ├── service/EmployeeService.class
    ├── model/Employee.class
    └── ...

注意:JAR 包不包含 pom.xml 中声明的依赖 JAR。运行时需要通过 classpath 或可执行 JAR 的 Class-Path 清单项引用依赖。

生活类比:产品装箱

想象一家电子产品工厂:

  • compile 阶段是生产电路板
  • test 阶段是质检,确保每块电路板功能正常
  • package 阶段是装箱:把电路板、说明书、保修卡装进一个包装盒(JAR),贴上标签(MANIFEST.MF),封箱待发货
  • 这个包装盒就是最终交给物流(运维李眉)的"可分发产物"

图示

上图展示了 mvn package 的核心流程:将 target/classes 中的编译产物和资源文件,连同生成的清单文件,压缩为单个 JAR 或 WAR 文件。packaging 类型决定了使用哪个插件和生成哪种格式的产物。


完整示例

场景

飞翔科技的 employee-system 项目开发完成,CTO 大翔要求小崔打包一个可部署的 JAR 文件,交给运维李眉部署到测试环境。

操作前:项目状态

pom.xml 中的关键配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.feixiang</groupId>
    <artifactId>employee-system</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>  <!-- 默认就是 jar,可省略 -->

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.2.0</version>
            </plugin>
        </plugins>
    </build>
</project>

操作步骤

步骤一:执行打包

mvn clean package

步骤二:观察输出

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< com.feixiang:employee-system >------------------
[INFO] Building employee-system 1.0.0
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
...
[INFO] --- compiler:3.11.0:compile (default-compile) @ employee-system ---
[INFO] Compiling 5 source files to target\classes
[INFO] 
[INFO] --- surefire:3.1.2:test (default-test) @ employee-system ---
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] --- jar:3.3.0:jar (default-jar) @ employee-system ---
[INFO] Building jar: C:\Users\xiaocui\workspace\employee-system\target\employee-system-1.0.0.jar
[INFO] 
[INFO] --- spring-boot:3.2.0:repackage (repackage) @ employee-system ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

关键输出解读:

  • jar:3.3.0:jar —— maven-jar-plugin 生成基础 JAR
  • spring-boot:3.2.0:repackage —— Spring Boot 插件将基础 JAR 重新打包为可执行 FAT JAR(包含所有依赖)
  • target\employee-system-1.0.0.jar —— 最终产物路径

package 前后的产物对比

package 前(仅 compile 后):

target/
├── classes/
│   ├── com/feixiang/...(.class 文件)
│   └── application.properties
└── test-classes/
    └── com/feixiang/...(测试 .class 文件)

package 后:

target/
├── classes/                          ← 编译产物(仍在)
├── test-classes/                     ← 测试编译产物(仍在)
├── surefire-reports/                 ← 测试报告(仍在)
├── employee-system-1.0.0.jar         ← ✅ 新生成的 JAR 包
├── employee-system-1.0.0.jar.original ← Spring Boot 原始 JAR(备份)
└── maven-archiver/
    └── pom.properties

跳过测试打包

在某些场景下(如快速验证打包流程、测试环境临时构建),可能需要跳过测试直接打包:

# 方式一:跳过测试执行(不编译也不运行测试)
mvn clean package -DskipTests

# 方式二:跳过测试运行(编译测试但不执行)
mvn clean package -Dmaven.test.skip=true

两者的区别:

参数测试代码编译测试执行使用场景
-DskipTests✅ 编译❌ 不执行需要测试类存在,但暂时不跑
-Dmaven.test.skip=true❌ 不编译❌ 不执行完全不需要测试,节省编译时间

注意:CTO 大翔明确规定,生产环境构建严禁跳过测试。-DskipTests 只允许在本地快速验证时使用。


易错点与常见问题

误区一:package 产物包含所有依赖

错误认知:"我执行 mvn package 生成的 JAR,直接 java -jar 就能运行,因为它包含了所有依赖。"

纠正:标准 Maven JAR 不包含依赖。maven-jar-plugin 生成的 JAR 只包含项目自身的 .class 文件和资源。要运行它,必须手动指定 classpath:

# 标准 JAR 需要指定 classpath
java -cp "target/employee-system-1.0.0.jar:lib/*" com.feixiang.EmployeeSystemApplication

如果你需要"FAT JAR"(包含所有依赖的可执行 JAR),需要使用额外插件:

  • Spring Boot 项目:spring-boot-maven-plugin 会自动生成 FAT JAR
  • 普通 Java 项目:使用 maven-shade-plugin 或 maven-assembly-plugin

误区二:package 会安装到本地仓库

错误认知:"我执行了 mvn package,其他项目就能引用这个 JAR 了。"

纠正:mvn package 只生成 JAR 到 target/ 目录,不会安装到本地仓库(~/.m2/repository)。要让其他项目引用,需要执行 mvn install,这将在下一章详细讲解。

误区三:WAR 包和 JAR 包可以随意切换

错误认知:"我把 pom.xml 里的 <packaging> 从 jar 改成 war,项目就能直接部署到 Tomcat 了。"

纠正:WAR 包需要项目具备 Web 应用结构(如 src/main/webapp/WEB-INF/web.xml),并且通常需要继承 spring-boot-starter-parent 或配置 maven-war-plugin。单纯改 packaging 标签,可能导致打包产物缺少必要的 Web 资源,部署时报错。

误区四:package 产物名可以随意改

典型问题:小崔希望生成的 JAR 文件名不包含版本号,方便脚本引用。

纠正:可以通过 maven-jar-plugin 的 <finalName> 配置自定义产物名:

<build>
    <finalName>employee-system</finalName>
</build>

这样生成的产物将是 target/employee-system.jar,而不是 target/employee-system-1.0.0.jar。


小结

mvn package 是 Maven 构建流程中生成可分发产物的核心命令。它将编译和测试通过的代码打包为 JAR 或 WAR 文件。核心要点:

  • mvn package 隐式执行 compile 和 test,确保产物质量
  • packaging 类型决定产物格式:jar → JAR,war → WAR
  • 标准 JAR 不包含依赖,需要额外插件生成 FAT JAR
  • -DskipTests 和 -Dmaven.test.skip=true 可跳过测试,但生产环境严禁使用
  • package 不安装到本地仓库,其他项目无法直接引用

本章与全局的关系:本章讲解了打包命令。下一章 mvn install 将展示如何将打包产物安装到本地仓库,供其他项目依赖使用。

上一页
mvn test
下一页
mvn clean