首页 开发教程 Java项目打包完整指南:从JAR到Docker全方位解析

Java项目打包完整指南:从JAR到Docker全方位解析

开发教程 2025年12月4日
423 浏览

一、Java打包工具全景图

在开始具体打包之前,我们先了解下主流的Java打包工具及其适用场景

工具 适用场景 特点 输出格式
javac + jar 简单学习项目 JDK内置,无需额外配置 JAR
Maven 企业级项目 强大的依赖管理和生命周期 JAR, WAR
Gradle 复杂大型项目 灵活配置,构建性能高 JAR, WAR, 多种格式
Spring Boot Maven Plugin Spring Boot应用 内嵌服务器,开箱即用 Executable JAR
jpackage 桌面应用程序 生成原生安装包 EXE, DMG, DEB
Docker 微服务部署 环境隔离,持续交付 Docker Image

二、传统JAR打包详解

2.1 项目结构准备

一个标准的Java项目结构如下:

MyApp/
├── src/
│   └── com/example/
│       ├── Main.java
│       └── util/
│           └── StringUtil.java
├── lib/ (第三方依赖)
└── resources/ (配置文件)

2.2 手动打包实战

对于简单的项目,我们可以使用JDK自带的工具手动打包:

# 1. 编译Java源代码
javac -d build/classes src/com/example/**/*.java

# 2. 创建清单文件(MANIFEST.MF)
cat > MANIFEST.MF << EOF
Manifest-Version: 1.0
Main-Class: com.example.Main
Created-By: Java Packager
EOF

# 3. 打包成JAR文件
jar cfm myapp.jar MANIFEST.MF -C build/classes .

# 4. 运行应用
java -jar myapp.jar

2.3 自动化构建脚本

为了提高效率,我们可以编写构建脚本:

#!/bin/bash
# build.sh - Java项目自动构建脚本

echo \" 开始构建Java项目...\"

# 清理构建目录
rm -rf build
mkdir -p build/classes

# 编译源码
echo \" 编译Java源码...\"
javac -d build/classes -sourcepath src src/com/example/**/*.java

# 拷贝资源文件
echo \" 拷贝资源文件...\"
cp -r resources/* build/classes/

# 创建清单文件
echo \" 生成清单文件...\"
cat > MANIFEST.MF << EOF
Manifest-Version: 1.0
Main-Class: com.example.Main
Class-Path: $(find lib -name \"*.jar\" | tr \'n\' \' \')
Build-Time: $(date)
EOF

# 打包JAR
echo \" 打包JAR文件...\"
jar cfm myapp.jar MANIFEST.MF -C build/classes .

# 清理临时文件
rm MANIFEST.MF

echo \" 构建完成!输出文件: myapp.jar\"

三、Maven标准化打包

Maven是Java领域最流行的构建工具,提供了标准化的项目结构和构建流程。

3.1 标准Maven项目结构

project/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/ (Java源代码)
│   │   │   └── com/example/
│   │   │       ├── Main.java
│   │   │       └── service/
│   │   └── resources/ (资源文件)
│   │       ├── application.properties
│   │       └── log4j2.xml
│   └── test/ (测试代码)
│       └── java/
└── target/ (构建输出目录)

3.2 基础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.example</groupId>
    <artifactId>myapp</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <properties>
        
        <java.version>11</java.version>
        <maven.compiler.version>3.8.1</maven.compiler.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.1</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3.3 创建可执行JAR的三种方式

方式一:使用maven-jar-plugin(依赖外置)

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.2.2</version>
    <configuration>
        <archive>
            <manifest>
                <mainClass>com.example.Main</mainClass>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
            </manifest>
        </archive>
    </configuration>
</plugin>

方式二:使用maven-assembly-plugin(胖JAR)

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifest>
                <mainClass>com.example.Main</mainClass>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

方式三:使用maven-shade-plugin(推荐)

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\">
                        <mainClass>com.example.Main</mainClass>
                    </transformer>
                    
                    <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

3.4 常用Maven命令

# 清理并打包
mvn clean package

# 跳过测试打包
mvn clean package -DskipTests

# 安装到本地仓库
mvn clean install

# 生成源码包和文档
mvn source:jar javadoc:jar

# 运行Spring Boot应用
mvn spring-boot:run

四、Web应用WAR包打包

对于Web应用,我们需要打包成WAR格式部署到Servlet容器。

4.1 Web项目结构

webapp/
├── pom.xml
├── src/
│   └── main/
│       ├── java/
│       │   └── com/example/
│       │       ├── controller/
│       │       ├── service/
│       │       └── config/
│       ├── resources/
│       └── webapp/ (Web资源)
│           ├── WEB-INF/
│           │   └── web.xml
│           ├── index.jsp
│           └── static/
│               ├── css/
│               ├── js/
│               └── images/

4.2 WAR打包配置


<packaging>war</packaging>

<build>
    <finalName>mywebapp</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.3.1</version>
            <configuration>
                
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <warSourceDirectory>src/main/webapp</warSourceDirectory>
            </configuration>
        </plugin>
    </plugins>
</build>

4.3 Spring Boot外部容器部署

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


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

五、Gradle现代化构建

Gradle以其简洁的DSL和出色的性能受到越来越多开发者的青睐。

5.1 基础build.gradle配置

plugins {
    id \'java\'
    id \'application\'
}

group = \'com.example\'
version = \'1.0.0\'
sourceCompatibility = \'11\'

repositories {
    mavenCentral()
}

dependencies {
    implementation \'org.springframework.boot:spring-boot-starter-web:2.7.0\'
    testImplementation \'org.springframework.boot:spring-boot-starter-test:2.7.0\'
}

application {
    mainClass = \'com.example.Main\'
}

5.2 创建胖JAR

// 使用Shadow插件创建胖JAR
plugins {
    id \'com.github.johnrengelman.shadow\' version \'7.1.2\'
}

shadowJar {
    archiveBaseName.set(\'myapp\')
    archiveClassifier.set(\'\')
    archiveVersion.set(\'\')
    mergeServiceFiles()
}

// 或者自定义任务
task customFatJar(type: Jar) {
    manifest {
        attributes \'Main-Class\': \'com.example.Main\'
    }
    archiveBaseName = \'myapp-all\'
    from { 
        configurations.runtimeClasspath.collect { 
            it.isDirectory() ? it : zipTree(it) 
        } 
    }
    with jar
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

5.3 常用Gradle命令

# 构建项目
./gradlew build

# 创建胖JAR
./gradlew shadowJar

# 清理构建
./gradlew clean

# 运行应用
./gradlew run

六、Docker容器化部署

容器化部署已经成为现代应用部署的标准方式。

6.1 多阶段构建Dockerfile

# 第一阶段:构建阶段
FROM maven:3.8.4-openjdk-11 AS builder
WORKDIR /app

# 拷贝pom文件并下载依赖(利用Docker缓存)
COPY pom.xml .
RUN mvn dependency:go-offline

# 拷贝源码并构建
COPY src ./src
RUN mvn clean package -DskipTests

# 第二阶段:运行阶段
FROM openjdk:11-jre-slim
WORKDIR /app

# 创建非root用户(安全考虑)
RUN groupadd -r spring && useradd -r -g spring spring
USER spring

# 从构建阶段拷贝JAR文件
COPY --from=builder /app/target/*.jar app.jar

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 
    CMD curl -f http://localhost:8080/actuator/health || exit 1

# JVM参数优化
ENV JAVA_OPTS=\"-Xmx512m -Xms256m -XX:+UseG1GC -Djava.security.egd=file:/dev/./urandom\"

# 暴露端口
EXPOSE 8080

# 启动命令
ENTRYPOINT [\"sh\", \"-c\", \"java $JAVA_OPTS -jar app.jar\"]

6.2 Docker Compose编排

version: \'3.8\'

services:
  app:
    build: .
    ports:
      - \"8080:8080\"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DATABASE_URL=jdbc:mysql://db:3306/myapp
    depends_on:
      - db
    networks:
      - app-network
    deploy:
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: myapp
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - app-network

volumes:
  db_data:

networks:
  app-network:
    driver: bridge

6.3 容器操作命令

# 构建镜像
docker build -t myapp:1.0.0 .

# 运行容器
docker run -d -p 8080:8080 --name myapp myapp:1.0.0

# 使用Docker Compose
docker-compose up -d

# 查看日志
docker logs -f myapp

# 进入容器调试
docker exec -it myapp bash

七、高级打包技巧

7.1 使用jpackage创建原生安装包(JDK 14+)

# 创建跨平台安装包
jpackage 
  --name MyApp 
  --input target/ 
  --main-jar myapp-1.0.0.jar 
  --main-class com.example.Main 
  --type app-image 
  --dest installers/ 
  --java-options \'-Xmx256m\'

# Windows特定选项
jpackage --type exe --win-console --icon app.ico

# macOS特定选项  
jpackage --type dmg --mac-package-identifier com.example.myapp

# Linux特定选项
jpackage --type deb --linux-package-name myapp

7.2 GraalVM原生镜像

FROM ghcr.io/graalvm/native-image:22 AS builder
WORKDIR /app

COPY . .
RUN mvn clean package -DskipTests

# 构建原生镜像
RUN native-image -jar target/myapp-1.0.0.jar 
    --no-fallback 
    --enable-https 
    -H:Name=myapp-native

# 运行阶段
FROM alpine:latest
RUN apk --no-cache add libstdc++
COPY --from=builder /app/myapp-native /app/myapp-native

EXPOSE 8080
ENTRYPOINT [\"/app/myapp-native\"]

八、最佳实践总结

8.1 版本管理


<properties>
    <java.version>11</java.version>
    <maven.compiler.version>3.8.1</maven.compiler.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

8.2 安全考虑

  • 使用非root用户运行容器
  • 定期更新基础镜像
  • 扫描镜像安全漏洞

8.3 性能优化

# 使用轻量级基础镜像
FROM openjdk:11-jre-slim

# 优化JVM参数
ENV JAVA_OPTS=\"-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0\"

8.4 CI/CD集成示例

name: Java CI/CD Pipeline

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up JDK 11
      uses: actions/setup-java@v2
      with:
        java-version: \'11\'
        distribution: \'temurin\'
        cache: \'maven\'
    
    - name: Build and Test
      run: mvn clean package
      
    - name: Build Docker Image
      run: docker build -t myapp:${{ github.sha }} .
      
    - name: Deploy to Registry
      run: |
        echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
        docker push myapp:${{ github.sha }}

结语

Java项目打包已经从简单的JAR文件发展到现代化的容器化部署。掌握这些打包技术对于Java开发者至关重要。无论是传统的Web应用还是现代的微服务,选择合适的打包方式都能大大提高开发和部署效率。

希望本文能为您提供全面的Java项目打包指导!如有任何问题,欢迎大家在评论区分享你的想法!!!

发表评论
暂无评论

还没有评论呢,快来抢沙发~

客服

点击联系客服 点击联系客服

在线时间:09:00-18:00

关注微信公众号

关注微信公众号
客服电话

400-888-8888

客服邮箱 122325244@qq.com

手机

扫描二维码

手机访问本站

扫描二维码
搜索