大家好,我是小悟。
一、JAR 和 WAR 打包的区别
JAR (Java ARchive)
- 独立运行:内嵌Tomcat/Jetty服务器,可直接通过
java -jar运行 - 微服务友好:适合云原生、容器化部署
- 简化部署:单个可执行文件,无需外部Web服务器
- 默认方式:Spring Boot 默认打包为可执行JAR
WAR (Web Application ARchive)
- 传统部署:需要外部Servlet容器(如Tomcat、WebLogic)
- 企业环境:适合需要部署到现有应用服务器的场景
- 共享资源:多个应用可共享服务器资源
- 配置分离:服务器配置与应用分离
二、详细打包部署步骤
项目结构
my-springboot-app/ ├── src/ │ └── main/ │ ├── java/com/example/ │ └── resources/ └── pom.xml 或 build.gradle
1. 打包为可执行JAR(默认方式)
Maven 配置 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>my-springboot-app</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <!-- 打包为JAR --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.5</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <!-- Spring Boot Maven 插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.example.MyApplication</mainClass> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Gradle 配置 (build.gradle)
plugins { id 'org.springframework.boot' version '3.1.5' id 'io.spring.dependency-management' version '1.1.3' id 'java' } group = 'com.example' version = '1.0.0' sourceCompatibility = '17' jar { enabled = true archiveClassifier = '' // 移除plain后缀 } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' } // 可执行JAR配置 bootJar { mainClass = 'com.example.MyApplication' archiveClassifier = '' }
主启动类
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
打包命令
# Maven mvn clean package # Gradle ./gradlew clean build
运行JAR
# 直接运行 java -jar target/my-springboot-app-1.0.0.jar # 指定配置文件 java -jar target/my-springboot-app-1.0.0.jar \ --spring.config.location=classpath:/,file:./config/ # 指定端口 java -jar target/my-springboot-app-1.0.0.jar \ --server.port=8081 # 生产环境运行(内存优化) java -Xms512m -Xmx1024m -jar target/my-springboot-app-1.0.0.jar \ --spring.profiles.active=prod
2. 打包为WAR(用于外部容器)
修改Maven配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>my-springboot-app</artifactId> <version>1.0.0</version> <packaging>war</packaging> <!-- 修改为WAR --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.5</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 排除内嵌Tomcat --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加Servlet API依赖(provided scope) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> <!-- 由外部容器提供 --> </dependency> </dependencies> <build> <finalName>myapp</finalName> <!-- WAR文件名称 --> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
修改启动类
package com.example; 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 MyApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(MyApplication.class); } public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
Gradle WAR配置
plugins { id 'org.springframework.boot' version '3.1.5' id 'io.spring.dependency-management' version '1.1.3' id 'java' id 'war' // 添加war插件 } group = 'com.example' version = '1.0.0' sourceCompatibility = '17' configurations { providedRuntime // 用于provided范围的依赖 } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' } war { archiveFileName = 'myapp.war' }
打包WAR
# Maven mvn clean package # Gradle ./gradlew clean build
部署到外部Tomcat
准备Tomcat服务器
# 下载Tomcat wget https://downloads.apache.org/tomcat/tomcat-10/v10.1.13/bin/apache-tomcat-10.1.13.tar.gz tar -xzf apache-tomcat-10.1.13.tar.gz cd apache-tomcat-10.1.13
部署WAR文件
# 复制WAR文件到webapps目录 cp target/myapp.war /opt/tomcat/webapps/ # 或者使用管理界面部署 # 访问 http://localhost:8080/manager/html
Tomcat配置优化(conf/server.xml)
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxThreads="200" minSpareThreads="10" enableLookups="false" acceptCount="100" disableUploadTimeout="true"/>
启动/停止Tomcat
# Linux ./bin/startup.sh ./bin/shutdown.sh # Windows bin\startup.bat bin\shutdown.bat
3. 配置文件管理
application.yml 示例
# 公共配置 spring: application: name: my-springboot-app # 开发环境 --- spring: config: activate: on-profile: dev server: port: 8080 logging: level: root: DEBUG # 生产环境 --- spring: config: activate: on-profile: prod server: port: 8080 compression: enabled: true mime-types: text/html,text/xml,text/plain,application/json logging: file: name: /var/log/myapp.log level: root: INFO
4. 容器化部署(Docker)
Dockerfile for JAR
# 使用多阶段构建 FROM eclipse-temurin:17-jdk-alpine as builder WORKDIR /app COPY mvnw . COPY .mvn .mvn COPY pom.xml . RUN ./mvnw dependency:go-offline COPY src ./src RUN ./mvnw clean package -DskipTests # 运行阶段 FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY --from=builder /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
Dockerfile for WAR + Tomcat
FROM tomcat:10.1-jdk17-temurin # 移除默认应用 RUN rm -rf /usr/local/tomcat/webapps/* # 复制WAR文件 COPY target/myapp.war /usr/local/tomcat/webapps/ROOT.war # 暴露端口 EXPOSE 8080 # 启动Tomcat CMD ["catalina.sh", "run"]
Docker Compose 示例
version: '3.8' services: app: build: . ports: - "8080:8080" environment: - SPRING_PROFILES_ACTIVE=prod - DB_HOST=mysql depends_on: - mysql networks: - app-network mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=rootpass - MYSQL_DATABASE=mydb volumes: - mysql-data:/var/lib/mysql networks: - app-network networks: app-network: driver: bridge volumes: mysql-data:
三、部署脚本示例
Linux 服务脚本(systemd)
# /etc/systemd/system/myapp.service [Unit] Description=My Spring Boot Application After=network.target [Service] Type=simple User=appuser WorkingDirectory=/opt/myapp ExecStart=/usr/bin/java -Xms512m -Xmx1024m -jar myapp.jar SuccessExitStatus=143 Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
部署脚本
#!/bin/bash # deploy.sh APP_NAME="my-springboot-app" JAR_PATH="target/$APP_NAME-1.0.0.jar" DEPLOY_DIR="/opt/$APP_NAME" BACKUP_DIR="$DEPLOY_DIR/backup" LOG_DIR="/var/log/$APP_NAME" # 创建目录 mkdir -p $DEPLOY_DIR $BACKUP_DIR $LOG_DIR # 备份旧版本 if [ -f "$DEPLOY_DIR/$APP_NAME.jar" ]; then TIMESTAMP=$(date +%Y%m%d_%H%M%S) mv "$DEPLOY_DIR/$APP_NAME.jar" "$BACKUP_DIR/$APP_NAME-$TIMESTAMP.jar" fi # 复制新版本 cp $JAR_PATH "$DEPLOY_DIR/$APP_NAME.jar" # 设置权限 chmod 755 "$DEPLOY_DIR/$APP_NAME.jar" # 重启服务 systemctl restart $APP_NAME # 检查状态 sleep 10 systemctl status $APP_NAME
四、总结对比
| 特性 | JAR 部署 | WAR 部署 |
| 部署方式 | 独立运行,内嵌容器 | 依赖外部Servlet容器 |
| 启动命令 | java -jar app.jar | 容器启动(如Tomcat) |
| 适合场景 | 微服务、云原生、容器化 | 传统企业环境、共享服务器 |
| 依赖管理 | 包含所有依赖(fat jar) | 部分依赖由容器提供 |
| 资源占用 | 每个应用独立容器 | 多个应用共享容器资源 |
| 热部署 | 需要重启整个应用 | Tomcat支持部分热部署 |
| 配置管理 | 应用自身管理 | 可与容器配置结合 |
| 监控 | Spring Boot Actuator | 容器管理界面 + Actuator |
选择建议:
- 选择JAR的情况:
- 微服务架构
- 容器化部署(Docker/K8s)
- 云原生应用
- 需要快速独立部署
- 无现有应用服务器
- 选择WAR的情况:
- 传统企业IT环境
- 已有Tomcat/WebLogic集群
- 需要与其他Java EE应用共享资源
- 运维团队熟悉传统部署模式
- 需要与旧系统集成
最佳实践:
- 对于新项目,优先考虑JAR部署,更符合现代架构
- 统一配置管理:无论JAR/WAR,使用外部配置文件
- 健康检查:集成Spring Boot Actuator用于监控
- 日志集中:使用Logback/SLF4J,日志输出到文件或日志系统
- 安全加固:生产环境关闭开发特性,使用HTTPS
- 自动化部署:结合CI/CD流水线实现自动化
通过合理的打包部署策略,可以确保Spring Boot应用在不同环境中的稳定运行和高效维护。
谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海