首页 / Spring Boot 入门教程 / 打包:Jar 与 War

Spring Boot 入门教程

打包:Jar 与 War

本教程共 48 篇 · 第 42 篇 · 更新于 2026-08-13 · 约 3 分钟阅读

Spring Boot打包可执行JarWar部署TomcatMaven部署

本节目标:理解可执行 Jar 的原理和内部结构,会用 Maven 打包并用 java -jar 运行,掌握 War 包部署到外部 Tomcat 的方法。

一个命令,从代码到制品

开发时用 mvn spring-boot:run,代码直接跑。上线不一样:需要把整个应用打成一个文件,拷到服务器上就能运行。

mvn clean package

执行完,target/ 目录下出现 demo-0.0.1-SNAPSHOT.jar。运行它:

java -jar target/demo-0.0.1-SNAPSHOT.jar

应用启动,Spring Boot 的 Banner 打出来,服务就起来了。这个 Jar 为什么能直接跑?普通 Jar 可没这个本事。

普通 Jar 与可执行 Jar

普通 Jar 只是 class 文件的压缩包,java -jar 能跑的前提是:META-INF/MANIFEST.MF 里有 Main-Class,且依赖的类都在。Spring Boot 应用依赖几十上百个第三方库,普通 Jar 装不下它们。

Spring Boot 的解法:repackagespring-boot-maven-pluginpackage 阶段把普通 Jar 重新打包:

  • 应用自己的 class 放进 BOOT-INF/classes/
  • 所有依赖 Jar 原样塞进 BOOT-INF/lib/,一个都不丢。
  • 清单文件指定启动器:Main-Class: org.springframework.boot.loader.launch.JarLauncher
  • 真正的入口写在 Start-Class 里,指向你的主类。

所以这个 Jar 叫 Boot-Jar,或者「胖 Jar」(fat jar)。用解压工具打开看看:

demo-0.0.1-SNAPSHOT.jar
├── META-INF/
│   └── MANIFEST.MF          # Main-Class 与 Start-Class
├── BOOT-INF/
│   ├── classes/             # 你的代码和资源文件
│   │   └── com/example/demo/...
│   └── lib/                 # 所有第三方依赖
│       ├── spring-boot-4.1.0.jar
│       └── spring-web-7.0.0.jar
└── org/springframework/boot/loader/
    └── launch/JarLauncher.class   # 启动器

JarLauncher 负责从嵌套的 BOOT-INF/lib 里加载依赖,再调用 Start-Class 指向的主类。这就是「一个 Jar 到处跑」的真相。

Note

4.x 的启动器包名是 org.springframework.boot.loader.launch,3.1 之前是 org.springframework.boot.loader。看到旧文章写的 JarLauncher 路径不一致,是版本差异。

打包配置在哪

spring-boot-maven-plugin 在初始项目里就配好了:

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

repackage 目标默认绑定在 package 阶段,不用额外配置。注意:只有这个插件在,Jar 才是可执行的;去掉它,打出来的是普通 Jar。

运行时的常用姿势

带参数启动:外部的配置优先级最高,直接命令行覆盖:

java -jar demo.jar --server.port=9090

指定 Profile

java -jar demo.jar --spring.profiles.active=prod

后台运行(Linux):

nohup java -jar demo.jar > app.log 2>&1 &

jarmode:拆开胖 Jar

胖 Jar 运行时要从嵌套 Jar 里加载类,有一点点开销。生产环境常常先解压再跑,启动更快。

Spring Boot 内置了 tools 模式,专门干这个:

java -Djarmode=tools -jar demo.jar list-layers
java -Djarmode=tools -jar demo.jar extract --destination application

extract 把 Jar 解压成目录结构,lib/ 文件夹放依赖,应用 class 单独放。解压后这样运行:

java -jar application/demo.jar

解压形态还支持 AOT 缓存和 CDS(类数据共享),能进一步压缩启动时间。这个在第 45 章展开。

War:回到传统 Servlet 容器

大多数场景 Jar 就够了。但有些公司要求部署到外部 Tomcat,和其他 Web 应用共用一个服务器。这时要打 War 包。

第一步:改打包方式

<packaging>war</packaging>

第二步:主类继承 SpringBootServletInitializer

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(DemoApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

SpringBootServletInitializer 是给外部容器用的入口。Tomcat 启动时找到它,由它来装配 Spring 应用。main 方法保留,本地还能用 java -jar 跑。

第三步:Tomcat 依赖改为 provided

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat-runtime</artifactId>
    <scope>provided</scope>
</dependency>

provided 意思是:打包时不要把 Tomcat 塞进去,服务器上已经有 Tomcat 了。不改成 provided,War 里带着内嵌 Tomcat,和外部容器冲突。

Warning

打了 War 之后,内嵌服务器只在 java -jar 运行时生效;部署到外部 Tomcat 时,由 Tomcat 负责 HTTP 服务,server.port 配置不再起作用,要改端口去改 Tomcat 的 server.xml

第四步:部署

mvn clean package

target/demo.war 拷到 Tomcat 的 webapps/ 目录,启动 Tomcat。访问路径是 http://localhost:8080/demo/,多了一段上下文路径,默认是 War 文件名。

Jar 还是 War:怎么选

  • 新项目、微服务、容器化:Jar,简单直接,java -jar 一条命令。
  • 老机房、共用 Tomcat:War,迁就现有运维体系。
  • 拿不准就 Jar。Spring Boot 的设计主线就是可执行 Jar,War 是兼容传统部署的选项。

小结

  • 可执行 Jar = 应用 class + 全部依赖 + 启动器,java -jar 直接跑。
  • Boot-Jar 结构:BOOT-INF/classes 放代码,BOOT-INF/lib 放依赖。
  • 生产环境可先 jarmode extract 解压再运行。
  • War 部署外部 Tomcat:改 packaging、继承 SpringBootServletInitializer、Tomcat 依赖改 provided