You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Web Start中Jersey Client发起意外请求问题排查

问题描述

使用的Jersey依赖

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.34</version>
    <type>jar</type>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.34</version>
</dependency>     
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-sse</artifactId>
    <version>2.34</version>
    <type>jar</type>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>2.34</version>
</dependency>        

应用背景

我的Java应用打包成包含所有依赖的uber-jar(JNLP文件中名为MyApplication-1.0.jar),是一款无界面应用,基于JAX-RS和Jersey库发起API请求,通过Java Web Start(基于AdoptOpenJDK/IcedTea-Web)在多设备上运行。

异常现象

部分设备运行应用一段时间(至少2-3天)后,应用仍存活的情况下会持续发起对MyApplication-1.0.jar的请求,服务器访问日志记录如下:

172.53.45.128 (81.53.51.24) - - [03/Jan/2020:12:49:01 +0000] "GET /MyApplication-1.0.jar HTTP/1.1" 200 20308737 "-" "Java/1.8.0_222"

测试验证

移除服务器上的JNLP和jar文件后,原本持续请求该jar的运行中设备,每次发起Rest API请求时都会抛出异常:

org.glassfish.jersey.internal.inject.InjectionManagerFactory: : java.io.FileNotFoundException: https://dev.myapplication.com/MyApplication-1.0.jar

栈跟踪信息

触发该请求的Jersey库代码位于org.glassfish.jersey.internal.inject.Injections类的lookupService方法,完整栈跟踪如下:

org.glassfish.jersey.internal.ServiceConfigurationError:
org.glassfish.jersey.internal.inject.InjectionManagerFactory: : 
java.io.FileNotFoundException: https://dev.myapplication.com/MyApplication-1.0.jar at 
org.glassfish.jersey.internal.ServiceFinder.fail(ServiceFinder.java:410) at 
org.glassfish.jersey.internal.ServiceFinder.parse(ServiceFinder.java:489) at 
org.glassfish.jersey.internal.ServiceFinder.access$400(ServiceFinder.java:132) at org.glassfish.jersey.internal.ServiceFinder$LazyObjectIterator.hasNext(ServiceFinder.java:686) at
org.glassfish.jersey.internal.inject.Injections.lookupService(Injections.java:88) at 
org.glassfish.jersey.internal.inject.Injections.lookupInjectionManagerFactory(Injections.java:73) at 
org.glassfish.jersey.internal.inject.Injections.createInjectionManager(Injections.java:44) at 
org.glassfish.jersey.client.ClientConfig$State.initRuntime(ClientConfig.java:413) at 
org.glassfish.jersey.internal.util.collection.Values$LazyValueImpl.get(Values.java:317) at 
org.glassfish.jersey.client.ClientConfig.getRuntime(ClientConfig.java:819) at 
org.glassfish.jersey.client.ClientRequest.getClientRuntime(ClientRequest.java:176) at 
org.glassfish.jersey.client.ClientRequest.getInjectionManager(ClientRequest.java:567) at 
org.glassfish.jersey.client.JerseyWebTarget.onBuilder(JerseyWebTarget.java:371) at 
org.glassfish.jersey.client.JerseyWebTarget.request(JerseyWebTarget.java:206) at 
org.glassfish.jersey.client.JerseyWebTarget.request(JerseyWebTarget.java:38) at 
com.mycompany.myapp.restclient.MyAppJerseyClient.updateUserData(MyAppJerseyClient.java:164) <------ 我的应用API请求

疑问

这是什么原因?为何在Java Web Start中运行的Jersey Client会出现这类异常请求?


原因分析与解决方案

核心原因

问题根源是Jersey的ServiceFinder机制与Java Web Start的类加载行为冲突:

  1. Jersey通过ServiceFinder读取META-INF/services下的配置文件来加载SPI实现(比如InjectionManagerFactory)。
  2. 在Java Web Start环境中,uber-jar的URL是远程地址,应用运行一段时间后,JWS的本地缓存可能失效或类加载器无法访问缓存文件,导致ServiceFinder尝试重新从远程URL读取jar内的服务配置。
  3. 每次发起API请求时,Jersey需要初始化或重新获取InjectionManager,触发ServiceFinder的查找逻辑,进而尝试下载整个jar包,最终在文件移除后抛出FileNotFoundException。

触发逻辑

从栈跟踪可见,调用JerseyWebTarget.request()时会触发ClientConfig的Runtime初始化,进而调用Injections.createInjectionManager(),该方法依赖ServiceFinder查找InjectionManagerFactory实现。如果此时JWS类加载器无法访问本地缓存的jar,就会发起远程请求。

解决方案

1. 显式指定InjectionManagerFactory(推荐)

创建Jersey Client时,直接指定实现类,跳过ServiceFinder的动态查找:

import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.JerseyClientBuilder;

// 显式配置InjectionManagerFactory
ClientConfig config = new ClientConfig();
config.property("jersey.config.inject.injectionManagerFactory", Hk2InjectionManagerFactory.class.getName());

// 基于配置构建Client
Client client = JerseyClientBuilder.createClient(config);

2. 优化Java Web Start缓存策略

在JNLP文件中添加配置,确保JWS稳定缓存jar文件:

  • 添加<offline-allowed/>标签,允许离线运行,强制缓存jar。
  • 设置<update check="background"/>,避免频繁检查更新,减少远程请求。

3. 拆分uber-jar

将应用与Jersey依赖拆分为多个独立jar,在JNLP中明确列出所有依赖,让JWS单独缓存每个jar,降低单个缓存失效的影响。

4. 升级Jersey版本

尝试升级到2.35及以上版本,后续版本针对JWS环境的类加载行为做了兼容性优化,可减少此类问题发生。


内容的提问来源于stack exchange,提问作者ansanes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:05:20