当前位置: 代码网 > it编程>编程语言>Java > Java项目打包成exe的4大主流方法完整指南

Java项目打包成exe的4大主流方法完整指南

2026年09月29日 • Java •我要评论
作为一名java开发者,你是否遇到过这样的场景:辛辛苦苦写了一个桌面工具,发给客户或者同事,对方双击jar包毫无反应,或者弹出一个黑窗口报错"找不到主类",又或者被告知"

作为一名java开发者,你是否遇到过这样的场景:辛辛苦苦写了一个桌面工具,发给客户或者同事,对方双击jar包毫无反应,或者弹出一个黑窗口报错"找不到主类",又或者被告知"你的电脑没有安装java"。这种交付体验不仅让用户抓狂,也让开发者颜面尽失。

本文将系统性地讲解java项目打包成exe的全部知识,从底层原理到实战操作,从工具选型到企业级ci/cd集成,让你看完就能直接上手,再也不用为java程序的交付问题发愁。

一、痛点场景:为什么java程序非要打成exe不可

1.1 真实场景还原

场景一:客户电脑没有jdk

你花了两周时间开发了一个数据报表生成工具,打包成jar发给客户。客户双击后没有任何反应,打电话过来质问:"你这软件是不是坏了?我双击了什么都没有。"你远程一看,客户电脑上连java都没装。你只能一步步教客户下载jdk、配置环境变量,折腾了一个小时,客户已经不耐烦了。

场景二:jdk版本不兼容

你的程序用java 17开发,客户电脑上装的是java 8。运行时直接抛出unsupportedclassversionerror,客户看不懂报错信息,只觉得你的软件"不好用"。

场景三:jar包双击没反应

即使客户装了正确版本的jdk,windows系统下jar文件的默认关联程序也可能不是java。双击后系统问你"用什么程序打开",普通用户根本不知道该选什么。

场景四:命令行启动体验差

你告诉客户"打开cmd,输入java -jar xxx.jar",客户一脸茫然。即使照着做了,一个黑窗口一直挂在那里,关掉黑窗口程序就退出了,体验极其不专业。

场景五:企业客户要求安装包

企业级客户的it部门有严格的软件分发规范,他们要求必须提供msi或exe安装包,能够静默安装、能在控制面板卸载、能创建桌面快捷方式。一个光秃秃的jar包根本过不了企业it的审核。

1.2 大白话总结

说白了,jar包就像一个"半成品菜",你得自己有锅(jdk)、会开火(命令行)才能做熟。而exe安装包就是"外卖成品",客户拿到手直接吃,什么都不用管。对于非技术用户来说,exe才是他们认知中"正常的软件"。

二、解决方案总览:四大主流方案一览

目前业界将java项目打包成exe主要有四大技术路线,各有适用场景:

方案技术本质代表工具适用场景
官方原生打包jre裁剪+原生启动器+安装包jpackage(jdk 14+)企业级桌面应用,需要正规安装包
轻量包装器生成exe启动壳,调用外部jrelaunch4j、jsmooth小型工具,用户机器已有jre
商业包装器功能丰富的exe生成工具exe4j、install4j商业软件,需要高级安装功能
aot原生编译提前编译为机器码,无需jvmgraalvm native imagecli工具、云原生、追求极致启动速度

接下来我们逐一深入讲解每个方案的原理和实操。

三、是什么:java打包exe的底层原理

3.1 专业解释

java程序本质上是运行在jvm(java虚拟机)上的字节码,不能直接被 操作系统执行。将java项目打包成exe,本质上是解决三个问题:

  1. 启动器问题:需要一个原生的windows可执行文件(.exe)作为入口,它负责找到jvm并启动java程序。
  2. 运行时问题:需要一个jre(java运行时环境)来执行字节码。可以依赖用户机器上已有的jre,也可以自带一个裁剪后的jre。
  3. 分发问题:需要将启动器、jre、应用jar包以及相关资源打包成一个用户友好的安装包。

3.2 大白话类比

把java程序想象成一部电影。jar包就是电影的数字胶片,jvm就是放映机,exe就是电影院。用户拿到jar包,就像拿到一卷胶片,自己家里没有放映机(没装jdk)就看不了。而exe安装包就像把胶片、迷你放映机、播放说明一起打包成一个"家庭影院套装",用户买回来插上电就能看。

3.3 生活案例

你买了一个宜家的书架,包装盒里有木板(jar包)、螺丝(依赖库)和说明书(manifest.mf)。但是你需要自己有螺丝刀(jdk)才能组装。如果宜家把书架预装好,再配一个电动螺丝刀一起送货 上门,那就是exe安装包的体验——开箱即用。

四、为什么用:打成exe的核心价值

4.1 用户体验层面

  • 零门槛运行:用户不需要安装jdk,不需要配置环境变量,不需要懂命令行。
  • 专业感强:有安装向导、桌面快捷方式、开始菜单条目、卸载程序,和普通windows软件一模一样。
  • 错误提示友好:启动器可以在找不到jre时给出友好的提示页面,而不是冷冰冰的命令行报错。

4.2 技术管控层面

  • 版本锁定:自带裁剪后的jre,确保用户运行的jdk版本和开发时一致,避免版本兼容问题。
  • jvm参数可控:可以在启动器中预设堆内存大小、gc策略等jvm参数,用户无法随意修改。
  • 进程管理规范:exe有独立的进程名,在任务管理器中显示为你的应用名称,而不是千篇一律的"java.exe"。

4.3 企业合规层面

  • 满足企业it分发要求:msi安装包支持组策略静默部署,符合企业软件管理规范。
  • 数字签名支持:可以对exe进行代码签名,消除windows smartscreen警告,提升信任度。
  • 自动更新集成:可以结合自动更新框架,实现软件的版本迭代管理。

五、演进史:java打包技术是如何发展到今天的

5.1 java 8及以前:javafxpackager时代

在java 8时代,oracle随jdk附带了一个叫做javafxpackager的工具(后来改名为javapackager),它可以将javafx应用打包成原生安装包。但这个工具有诸多限制:仅支持javafx应用、配置繁琐、生成的安装包体积大、跨平台支持差。大多数开发者还是依赖第三方工具如launch4j、exe4j来完成打包。

5.2 java 9:jlink与模块系统的革命

java 9引入了jpms(java平台模块系统),同时提供了jlink工具。jlink可以根据应用实际使用的模块,裁剪出一个最小化的jre运行时镜像。以前一个完整的jre动辄200mb以上,使用jlink裁剪后可以压缩到40mb甚至更小。这为java应用的轻量化分发奠定了基础。

5.3 java 14:jpackage首次亮相(孵化阶段)

jep 343提案引入了jpackage工具,作为java 14的孵化特性。jpackage整合了jlink的裁剪能力和原生打包能力,可以直接生成windows的exe/msi、macos的dmg/pkg、linux的deb/rpm安装包。这是oracle官方首次提供一个功能完整的打包工具,但由于是孵化阶段,api和行为还可能变化,企业用户持观望态度。

5.4 java 17:jpackage正式稳定

在java 17这个lts(长期支持)版本中,jpackage正式转正,成为jdk的标准工具。从此java开发者有了一个官方、稳定、跨平台的打包解决方案。配合jlink的模块裁剪能力,jpackage成为企业级java桌面应用打包的首选方案。

5.5 现代:graalvm native image的崛起

近年来,graalvm的native image技术逐渐成熟。它采用aot(ahead-of-time,提前编译)技术,在构建时就将java字节码编译成原生机器码,生成的exe完全不需要jvm即可运行,启动时间从秒级降到毫秒级,内存占用也大幅降低。虽然在反射、动态代理等场景需要额外配置,但对于cli工具、微服务等场景,native image正在成为新的趋势。

六、怎么用:三大方案实战教程

6.1 方案一:jpackage(官方推荐,企业首选)

jpackage是jdk 14+自带的官方打包工具,java 17及以上版本稳定可用。它能够自动调用jlink裁剪jre,并生成原生安装包。

6.1.1 环境准备

首先确认你的jdk版本:

java -version

输出应类似:

java version "17.0.9" lts

在windows上打包exe/msi还需要安装wix toolset 3.x(注意不是wix 4),下载地址:https://wixtoolset.org/releases/

安装后将wix的bin目录加入系统path,验证:

light.exe -help

6.1.2 第一步:构建可执行jar包

使用maven的maven-shade-plugin将所有依赖打入一个可执行jar:

<build>
    <plugins>
        <plugin>
            <groupid>org.apache.maven.plugins</groupid>
            <artifactid>maven-shade-plugin</artifactid>
            <version>3.5.1</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.myapp.main</mainclass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行构建:

mvn clean package

构建完成后,在target/目录下会生成一个包含所有依赖的可执行jar包,例如myapp-1.0.jar。

6.1.3 第二步:使用jpackage生成exe安装包

创建一个input目录,将jar包放进去:

mkdir input
copy target\myapp-1.0.jar input\

执行jpackage命令:

jpackage ^
  --type exe ^
  --input input ^
  --dest output ^
  --name myapp ^
  --main-jar myapp-1.0.jar ^
  --main-class com.example.myapp.main ^
  --app-version 1.0.0 ^
  --vendor "羽师科技" ^
  --description "我的java桌面应用" ^
  --icon app.ico ^
  --java-options "-xmx512m" ^
  --win-dir-chooser ^
  --win-menu ^
  --win-shortcut

参数说明:

参数说明
--type exe生成exe安装包,也可以用msi
--input包含jar包的输入目录
--dest输出目录
--name应用名称
--main-jar主jar包文件名
--main-class主类全限定名
--app-version应用版本号
--icon应用图标(.ico格式)
--java-options传递给jvm的参数
--win-dir-chooser允许用户选择安装目录
--win-menu添加到开始菜单
--win-shortcut创建桌面快捷方式

执行完成后,在output/目录下会生成myapp-1.0.0.exe安装包。用户双击即可安装,安装后桌面和开始菜单都会出现快捷方式。

6.1.4 第三步:生成免安装的应用镜像

如果你不想做安装包,只想生成一个解压即用的文件夹,可以使用--type app-image:

jpackage ^
  --type app-image ^
  --input input ^
  --dest output ^
  --name myapp ^
  --main-jar myapp-1.0.jar ^
  --main-class com.example.myapp.main ^
  --icon app.ico

这会在output/myapp/目录下生成一个完整的应用文件夹,包含裁剪后的jre和启动器,用户直接双击myapp.exe即可运行,无需安装。

6.1.5 maven插件集成(企业级用法)

在企业项目中,可以使用org.panteleyev:jpackage-maven-plugin将jpackage集成到maven构建流程中:

<plugin>
    <groupid>org.panteleyev</groupid>
    <artifactid>jpackage-maven-plugin</artifactid>
    <version>1.6.0</version>
    <configuration>
        <name>myapp</name>
        <appversion>${project.version}</appversion>
        <vendor>羽师科技</vendor>
        <destination>target/dist</destination>
        <input>target</input>
        <mainjar>${project.build.finalname}.jar</mainjar>
        <mainclass>com.example.myapp.main</mainclass>
        <javaoptions>
            <option>-xmx512m</option>
        </javaoptions>
        <type>exe</type>
        <winmenu>true</winmenu>
        <winshortcut>true</winshortcut>
        <windirchooser>true</windirchooser>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>jpackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

这样执行mvn clean package就会自动完成编译、打jar、生成exe的全过程。

6.2 方案二:launch4j(轻量快速,适合小工具)

launch4j是一个开源的轻量级java exe包装器,它生成的exe本质上是一个启动器壳,负责查找jre并启动jar包。launch4j本身不打包jre,但可以指定旁置的jre目录。

6.2.1 下载安装

从官网下载:https://launch4j.sourceforge.net/

解压后即可使用,提供gui界面和命令行两种模式。

6.2.2 编写配置文件

创建launch4j-config.xml:

<?xml version="1.0" encoding="utf-8"?>
<launch4jconfig>
  <dontwrapjar>false</dontwrapjar>
  <headertype>gui</headertype>
  <jar>target\myapp-1.0.jar</jar>
  <outfile>output\myapp.exe</outfile>
  <errtitle>myapp 启动错误</errtitle>
  <cmdline></cmdline>
  <chdir>.</chdir>
  <priority>normal</priority>
  <downloadurl>https://www.java.com/download/</downloadurl>
  <supporturl></supporturl>
  <stayalive>false</stayalive>
  <restartoncrash>false</restartoncrash>
  <manifest></manifest>
  <icon>app.ico</icon>
  <classpath>
    <mainclass>com.example.myapp.main</mainclass>
  </classpath>
  <jre>
    <path>jre</path>
    <bundledjre64bit>true</bundledjre64bit>
    <bundledjreasfallback>false</bundledjreasfallback>
    <minversion>17</minversion>
    <maxversion></maxversion>
    <jdkpreference>preferjre</jdkpreference>
    <runtimebits>64</runtimebits>
  </jre>
  <heapsize>512</heapsize>
  <heapmaxsize>1024</heapmaxsize>
  <versioninfo>
    <fileversion>1.0.0.0</fileversion>
    <txtfileversion>1.0.0</txtfileversion>
    <filedescription>我的java桌面应用</filedescription>
    <copyright>copyright 2026 羽师科技</copyright>
    <productversion>1.0.0.0</productversion>
    <txtproductversion>1.0.0</txtproductversion>
    <productname>myapp</productname>
    <companyname>羽师科技</companyname>
  </versioninfo>
</launch4jconfig>

关键配置说明:

  • <headertype>gui</headertype>:gui应用,不显示黑窗口;如果是命令行工具用console。
  • <path>jre</path>:优先使用exe同级目录下的jre文件夹,实现自带jre。
  • <minversion>17</minversion>:最低jre版本要求。
  • <downloadurl>:找不到合适jre时跳转到的下载页面。

6.2.3 执行打包

命令行方式:

launch4jc.exe launch4j-config.xml

或者打开launch4j的gui界面,导入配置文件,点击"build wrapper"按钮。

6.2.4 自带jre实现免安装运行

使用jlink裁剪一个最小jre:

jlink ^
  --add-modules java.base,java.desktop,java.logging ^
  --output jre ^
  --strip-debug ^
  --compress=2 ^
  --no-header-files ^
  --no-man-pages

将生成的jre文件夹和myapp.exe放在同一目录下,整个文件夹拷贝到任何windows机器上都能直接运行,无需安装jdk。

6.3 方案三:graalvm native image(极致性能,无需jvm)

graalvm native image采用aot编译技术,在构建时将java字节码直接编译成原生机器码,生成的exe完全不依赖jvm,启动速度极快,内存占用极低。

6.3.1 环境准备

下载并安装graalvm(建议graalvm for jdk 17或21):https://www.graalvm.org/downloads/

设置java_home指向graalvm安装目录,并将bin加入path。验证:

java -version
native-image --version

在windows上还需要安装visual studio build tools,包含windows sdk和msvc编译器。安装时勾选"使用c++的桌面开发"工作负载。

6.3.2 简单示例:hello world

编写helloworld.java:

public class helloworld {
    public static void main(string[] args) {
        system.out.println("hello, native image!");
    }
}

编译并生成原生exe:

javac helloworld.java
native-image helloworld

这会生成helloworld.exe,直接运行:

helloworld.exe

输出:

hello, native image!

启动时间通常在10毫秒以内,内存占用只有几mb。

6.3.3 从jar包生成原生exe

对于已有jar包的项目:

native-image -jar target/myapp-1.0.jar myapp

6.3.4 maven插件集成

在pom.xml中添加graalvm原生镜像插件:

<profiles>
    <profile>
        <id>native</id>
        <build>
            <plugins>
                <plugin>
                    <groupid>org.graalvm.buildtools</groupid>
                    <artifactid>native-maven-plugin</artifactid>
                    <version>0.10.1</version>
                    <extensions>true</extensions>
                    <configuration>
                        <mainclass>com.example.myapp.main</mainclass>
                        <buildargs>
                            <buildarg>--no-fallback</buildarg>
                            <buildarg>--initialize-at-build-time</buildarg>
                        </buildargs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>build-native</id>
                            <phase>package</phase>
                            <goals>
                                <goal>compile-no-fork</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

执行原生编译:

mvn clean package -pnative

6.3.5 反射配置(重要)

native image在编译时会做静态可达性分析,无法自动识别反射调用。如果你的代码使用了反射、动态代理、jni等特性,需要提供配置文件。

在src/main/resources/meta-inf/native-image/目录下创建reflect-config.json:

[
  {
    "name": "com.example.myapp.model.user",
    "alldeclaredconstructors": true,
    "allpublicconstructors": true,
    "alldeclaredmethods": true,
    "allpublicmethods": true,
    "alldeclaredfields": true,
    "allpublicfields": true
  }
]

也可以使用java agent自动收集配置:

java -agentlib:native-image-agent=config-output-dir=src/main/resources/meta-inf/native-image -jar target/myapp-1.0.jar

运行程序覆盖所有功能路径后,agent会自动生成所需的配置文件。

七、竞品对比:四大方案优劣势深度对比

对比维度jpackagelaunch4jexe4jgraalvm native image
是否官方是(jdk 14+自带)否(开源第三方)否(商业软件)否(oracle graalvm)
技术本质jre裁剪+原生启动器+安装包轻量exe启动壳功能丰富的exe启动壳aot编译为原生机器码
是否需要jvm是(自带裁剪jre)是(依赖外部或旁置jre)是(依赖外部或旁置jre)否(完全原生)
启动速度正常(jvm启动,约1-3秒)正常(jvm启动)正常(jvm启动)极快(毫秒级)
内存占用标准jvm(约100-300mb)标准jvm标准jvm极低(约10-50mb)
安装包体积中等(约40-80mb,含裁剪jre)极小(exe仅几十kb,不含jre)小(exe约1-2mb,不含jre)中等(约20-60mb)
反射/动态代理支持完全支持完全支持完全支持需要额外配置
跨平台打包否(必须在目标os上构建)是(可在linux/macos生成windows exe)否(仅windows)否(必须在目标os上构建)
生成安装包支持(exe/msi/dmg/deb/rpm)不支持(仅生成exe)不支持(仅生成exe,需配合install4j)不支持(仅生成exe)
学习曲线中等简单简单(gui向导)较陡
商业授权免费(gplv2 + ce)免费(mit/bsd)收费(约$199起)免费(社区版)/企业版收费
最佳适用场景企业级桌面应用、javafx/swing小型工具、用户已有jre商业软件、需要高级功能cli工具、微服务、云原生

7.1 选型建议

  • 如果你做企业级桌面应用:选jpackage,官方稳定,安装包规范,自动裁剪jre。
  • 如果你做小工具且用户机器有jre:选launch4j,轻量快速,配置简单。
  • 如果你做商业软件且预算充足:exe4j/install4j组合,功能最丰富,支持自动更新。
  • 如果你做cli工具或追求极致性能:选graalvm native image,毫秒启动,低内存。

八、企业项目实战:ci/cd自动化打包流水线

在企业项目中,手动打包exe是不可接受的。需要将打包流程集成到ci/cd流水线中,实现代码提交后自动构建、自动测试、自动打包、自动发布。

8.1 gitlab ci配置示例

stages:
  - build
  - test
  - package
  - release
variables:
  maven_opts: "-dmaven.repo.local=.m2/repository"
# 构建jar包
build_jar:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn clean package -dskiptests
  artifacts:
    paths:
      - target/*.jar
    expire_in: 1 week
# 运行单元测试
run_tests:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn test
  artifacts:
    reports:
      junit: target/surefire-reports/*.xml
# windows平台打包exe
package_windows_exe:
  stage: package
  tags:
    - windows
  script:
    - choco install wixtoolset -y
    - mkdir input
    - copy target\myapp-1.0.jar input\
    - jpackage --type exe --input input --dest dist --name myapp --main-jar myapp-1.0.jar --main-class com.example.myapp.main --app-version %ci_commit_tag% --vendor "羽师科技" --icon app.ico --win-dir-chooser --win-menu --win-shortcut
  artifacts:
    paths:
      - dist/*.exe
    expire_in: 1 month
  only:
    - tags
# macos平台打包dmg
package_macos_dmg:
  stage: package
  tags:
    - macos
  script:
    - mkdir input
    - cp target/myapp-1.0.jar input/
    - jpackage --type dmg --input input --dest dist --name myapp --main-jar myapp-1.0.jar --main-class com.example.myapp.main --app-version $ci_commit_tag --vendor "羽师科技" --icon app.icns
  artifacts:
    paths:
      - dist/*.dmg
    expire_in: 1 month
  only:
    - tags
# 发布到制品库
release:
  stage: release
  image: curlimages/curl:latest
  script:
    - curl -u $nexus_user:$nexus_pass --upload-file dist/myapp-$ci_commit_tag.exe https://nexus.example.com/repository/releases/com/example/myapp/$ci_commit_tag/myapp-$ci_commit_tag.exe
  only:
    - tags

8.2 jenkins pipeline配置示例

pipeline {
    agent any
    tools {
        jdk 'jdk-17'
        maven 'maven-3.9'
    }
    environment {
        app_name = 'myapp'
        app_version = "${env.build_number}"
    }
    stages {
        stage('checkout') {
            steps {
                git branch: 'main', url: 'https://git.example.com/myapp.git'
            }
        }
        stage('build & test') {
            steps {
                bat 'mvn clean package'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                }
            }
        }
        stage('package exe') {
            agent { label 'windows' }
            steps {
                bat '''
                    mkdir input
                    copy target\\myapp-1.0.jar input\\
                    jpackage --type exe ^
                        --input input ^
                        --dest dist ^
                        --name %app_name% ^
                        --main-jar myapp-1.0.jar ^
                        --main-class com.example.myapp.main ^
                        --app-version %app_version% ^
                        --vendor "羽师科技" ^
                        --icon app.ico ^
                        --win-dir-chooser ^
                        --win-menu ^
                        --win-shortcut
                '''
            }
            post {
                success {
                    archiveartifacts artifacts: 'dist/*.exe', fingerprint: true
                }
            }
        }
        stage('deploy') {
            steps {
                echo '部署到下载服务器...'
            }
        }
    }
}

8.3 企业级最佳实践

  1. 多平台矩阵构建:使用不同操作系统的runner,同时构建windows exe、macos dmg、linux deb。
  2. 版本号统一管理:从git tag或ci构建号获取版本号,确保安装包版本和代码版本一致。
  3. 代码签名:在打包后对exe进行数字签名,消除windows smartscreen警告。
  4. 自动更新集成:配合update4j或sparkle等框架,实现软件自动更新。
  5. 制品归档:将每个版本的安装包归档到nexus或artifactory,支持历史版本回溯。
  6. 灰度发布:先发布给内部测试用户,验证无误后再全量发布。

九、常用场景与实战技巧

9.1 场景一:swing桌面应用打包

swing应用打包时需要注意中文乱码问题,在jpackage的--java-options中添加文件编码参数:

jpackage ^
  --type exe ^
  --input input ^
  --dest output ^
  --name myswingapp ^
  --main-jar myapp.jar ^
  --main-class com.example.main ^
  --java-options "-dfile.encoding=utf-8 -dsun.jnu.encoding=utf-8 -xmx512m"

9.2 场景二:javafx应用打包

javafx从jdk 11开始被移除,需要单独引入依赖。使用jpackage时需要在--java-options中指定javafx模块路径:

jpackage ^
  --type exe ^
  --input input ^
  --dest output ^
  --name myjavafxapp ^
  --main-jar myapp.jar ^
  --main-class com.example.main ^
  --java-options "--module-path lib --add-modules javafx.controls,javafx.fxml -xmx512m"

也可以使用javafx-maven-plugin的jlink目标先生成包含javafx模块的运行时镜像,再用jpackage打包。

9.3 场景三:spring boot命令行工具打包

spring boot应用可以使用graalvm native image打包成原生exe,实现毫秒启动:

<plugin>
    <groupid>org.graalvm.buildtools</groupid>
    <artifactid>native-maven-plugin</artifactid>
</plugin>

执行:

mvn -pnative native:compile

生成的exe在target/目录下,直接运行即可,无需jvm。

9.4 场景四:带外部配置文件的应用

如果应用需要读取外部配置文件(如config.properties),在jpackage中使用--input目录将配置文件一起打包:

mkdir input
copy target\myapp.jar input\
copy config.properties input\
jpackage --type app-image --input input --dest output --name myapp --main-jar myapp.jar

安装后配置文件会位于应用目录下,用户可以直接编辑。

9.5 常用技巧

技巧一:减小安装包体积

使用jlink的--compress=2和--strip-debug选项,可以将jre体积进一步压缩:

jlink --add-modules java.base,java.desktop --output jre --strip-debug --compress=2 --no-header-files --no-man-pages

技巧二:自定义安装界面

jpackage支持通过--resource-dir自定义安装界面资源,包括欢迎页、许可协议等:

jpackage --type exe --input input --dest output --name myapp --main-jar myapp.jar --resource-dir custom-resources

技巧三:设置jvm堆内存

在jpackage中通过--java-options预设jvm参数:

jpackage --type exe --input input --dest output --name myapp --main-jar myapp.jar --java-options "-xms256m -xmx1024m -xx:+useg1gc"

十、面试官高频面试题

面试题一:java项目打包成exe有哪些方案?各自的优缺点是什么?

参考答案:

主要有四大方案:

  • jpackage:jdk 14+官方工具,java 17稳定。优点是官方支持、自动裁剪jre、生成原生安装包(exe/msi/dmg/deb/rpm)、跨平台。缺点是必须在目标操作系统上构建,不能交叉编译。适合企业级桌面应用。
  • launch4j:开源轻量包装器。优点是体积小、配置简单、可以在linux/macos上交叉生成windows exe。缺点是本身不打包jre,需要用户机器有jre或旁置jre文件夹,不生成安装包。适合小型工具。
  • exe4j/install4j:商业工具。优点是功能丰富、gui向导、支持自动更新。缺点是收费,仅支持windows。适合商业软件。
  • graalvm native image:aot编译。优点是生成真正的原生二进制,无需jvm,毫秒级启动,内存占用极低。缺点是反射、动态代理等需要额外配置,构建时间长,对某些框架支持不完善。适合cli工具和云原生场景。

面试题二:jpackage和jlink有什么区别和联系?

参考答案:

  • jlink是java 9引入的工具,用于根据应用实际使用的模块,裁剪出一个最小化的jre运行时镜像。它只负责生成运行时,不负责生成启动器和安装包。
  • jpackage是java 14引入的工具,用于将java应用打包成原生安装包。jpackage内部会自动调用jlink来裁剪jre,然后将裁剪后的jre、应用jar、原生启动器一起打包成安装包。

简单说,jlink是jpackage的底层依赖之一,jpackage = jlink + 原生启动器 + 安装包生成。

面试题三:为什么jpackage不能在linux上打包windows的exe?

参考答案:

jpackage生成的是平台原生的安装包,它依赖目标平台的原生工具链。在windows上生成exe/msi需要调用wix toolset,在macos上生成dmg需要调用系统的磁盘映像工具,在linux上生成deb/rpm需要调用dpkg/rpm工具。这些工具都是平台相关的,无法跨平台调用。因此jpackage必须在目标操作系统上运行,不能交叉编译。如果需要多平台打包,需要使用多平台的ci/cd构建矩阵。

面试题四:graalvm native image的工作原理是什么?有什么限制?

参考答案:

工作原理: native image采用aot(ahead-of-time)提前编译技术。在构建时,它通过静态分析扫描应用的字节码,找出所有可达的代码路径,然后将这些字节码直接编译成目标平台的原生机器码。同时它会在构建时初始化一部分类,将堆对象序列化到镜像中。最终生成的是一个完全独立的原生可执行文件,不需要jvm即可运行。

主要限制:

  1. 反射支持不完善:编译时无法预知动态加载的类,需要通过reflect-config.json手动配置。
  2. 动态代理需要配置:需要通过proxy-config.json声明动态代理接口。
  3. jni需要配置:需要通过jni-config.json配置。
  4. 类加载器限制:不支持运行时创建自定义类加载器加载新类。
  5. 构建时间长:aot编译比普通javac编译慢得多,大项目可能需要几十分钟。
  6. 峰值性能可能低于jit:对于长时间运行的服务,jvm的jit编译器经过运行时优化后峰值性能可能更高。

面试题五:如何减小java应用打包后的体积?

参考答案:

  1. 使用jlink裁剪jre:只包含应用实际需要的模块,而不是完整的jdk。一个最小的java.base模块jre只有约20mb。
  2. 使用--strip-debug:移除调试信息,减小体积。
  3. 使用--compress=2:对jre进行zip压缩。
  4. 使用--no-header-files和--no-man-pages:移除头文件和man手册。
  5. 排除未使用的依赖:在maven/gradle中排查并排除未使用的依赖库。
  6. 使用proguard混淆优化:对字节码进行优化和混淆,移除未使用的代码。
  7. 使用graalvm native image:aot编译后的原生二进制体积通常比jre+jar小。

面试题六:launch4j生成的exe和jpackage生成的exe有什么本质区别?

参考答案:

launch4j生成的exe只是一个轻量级的启动器壳(通常只有几十kb),它本身不包含jre,运行时需要在系统中查找或在指定路径查找jre,然后调用jvm来执行jar包。jar包可以被打包进exe内部,也可以放在外部。

jpackage生成的exe是一个完整的安装包,安装后会在目标机器上部署一个完整的应用目录,包含:原生启动器exe、裁剪后的jre运行时、应用jar包和资源文件。用户机器上完全不需要安装jdk。

简单说,launch4j的exe是"借鸡生蛋"(用系统的jre),jpackage的exe是"自带厨房"(自带裁剪jre)。

总结

java项目打包成exe,从早期的第三方工具群雄割据,到如今jpackage官方方案一统江湖,再到graalvm native image开辟原生编译新赛道,技术生态已经非常成熟。选择哪种方案,取决于你的应用场景、用户群体和性能要求。对于大多数企业级桌面应用,jpackage是目前最稳妥、最规范的选择;对于追求极致性能的cli工具,graalvm native image值得投入研究。

以上就是java项目打包成exe的4大主流方法完整指南的详细内容,更多关于java打包成exe的资料请关注代码网其它相关文章!

赞 (0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com