如何通过Java Web Start(JNLP)启动Spring Boot API JAR包?
问题描述
尝试通过JNLP启动包含Spring Boot API的JAR包时,抛出以下异常:
java.lang.IllegalStateException: Unable to determine code source archive from \\localhost:8080\webstart\printer-api\printer-api.jar at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:126) at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:38) at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:35) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.sun.javaws.Launcher.executeApplication(Unknown Source) at com.sun.javaws.Launcher.executeMainClass(Unknown Source) at com.sun.javaws.Launcher.doLaunchApp(Unknown Source) at com.sun.javaws.Launcher.run(Unknown Source)
使用的JNLP文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <jnlp spec="1.0+" codebase="http://localhost:8080/webstart/printer-api" href="printer-api.jnlp"> <information> <title>PrinterAPi</title> <vendor>ADM</vendor> <homepage href="http://localhost:8080/webstart/printer-api"/> <description>Web Start</description> <offline-allowed/> </information> <security> <all-permissions/> </security> <resources> <j2se version="1.8+" href="http://java.sun.com/products/autodl/j2se"/> <jar href="printer-api.jar" /> </resources> <application-desc main-class="org.springframework.boot.loader.JarLauncher" /> </jnlp>
已查阅相关问题但未获得明确解决方案,现寻求通过Java Web Start/JNLP启动Spring Boot API JAR包的可行方案。
可行解决方案
方案1:改用普通JAR替代Spring Boot可执行JAR
Spring Boot默认生成的可执行JAR带特殊加载逻辑,和JNLP的代码源处理逻辑冲突。调整打包配置生成普通JAR,同时单独处理依赖:
- 在
pom.xml里给spring-boot-maven-plugin添加classifier参数,生成普通JAR:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <classifier>exec</classifier> </configuration> </plugin>
- 执行打包后会得到两个文件:
printer-api.jar(包含业务代码的普通JAR)和printer-api-exec.jar(原可执行JAR) - 修改JNLP的
main-class为你的Spring Boot应用主类(比如com.example.PrinterApiApplication),并把所有依赖JAR添加到<resources>的<jar>标签里(可用Maven的dependency:copy-dependencies命令把依赖批量复制到webstart目录)
方案2:自定义启动器适配JNLP路径格式
异常显示JNLP把JAR路径转成了UNC格式(\\localhost...),Spring Boot的JarLauncher无法识别这种格式,自定义启动类处理:
- 写一个继承
JarLauncher的自定义启动类,重写createArchive方法适配UNC路径:
public class JnlpJarLauncher extends JarLauncher { @Override protected Archive createArchive() throws Exception { CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); if (codeSource != null) { URL location = codeSource.getLocation(); // 把UNC路径转成合法的file URL格式 String path = location.getPath(); if (path.startsWith("\\\\")) { path = "file:///" + path.replace("\\", "/"); location = new URL(path); } return createArchive(location); } throw new IllegalStateException("Unable to determine code source archive"); } public static void main(String[] args) throws Exception { new JnlpJarLauncher().launch(args); } }
- 把这个类放进项目,打包到Spring Boot可执行JAR里
- 修改JNLP的
main-class为这个自定义类的全限定名(比如com.example.JnlpJarLauncher)
方案3:调整JNLP的路径配置
修改JNLP文件的codebase和JAR引用格式,确保路径被正确解析:
- 把
codebase改成jnlp://localhost:8080/webstart/printer-api/(注意结尾加斜杠) - 或者给
jar标签使用绝对URL:
<resources> <j2se version="1.8+" href="http://java.sun.com/products/autodl/j2se"/> <jar href="http://localhost:8080/webstart/printer-api/printer-api.jar" /> </resources>
- 同时确保服务器配置了正确的MIME类型:添加
application/x-java-jnlp-file对应.jnlp后缀
方案4:用JNLP扩展机制拆分依赖
把Spring Boot的依赖打包成独立的JNLP扩展,避免和主JAR的加载逻辑冲突:
- 写一个扩展JNLP文件(比如
spring-boot-deps.jnlp),里面列出所有Spring Boot依赖JAR - 在主JNLP里引入这个扩展:
<resources> <j2se version="1.8+" href="http://java.sun.com/products/autodl/j2se"/> <extension name="spring-boot-deps" href="spring-boot-deps.jnlp"/> <jar href="printer-api.jar" /> </resources>
- 主JAR用普通JAR格式,
main-class设置为你的Spring Boot应用主类
内容的提问来源于stack exchange,提问作者Ariel
相关产品推荐
相关产品推荐

