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

Embedded Jetty+2个Jersey Servlet:导出Jar后第二个服务报500错误求助

解决Embedded Jetty + Jersey 打包JAR后Servlet 500错误的问题

看起来你遇到的核心问题是Maven Shade插件打包时的资源文件冲突——Eclipse运行时依赖是分散加载的,而Shade打包成单一JAR时,默认会覆盖重复的资源文件,尤其是Jersey依赖的SPI(服务提供者接口)配置文件,这直接导致其中一个Servlet无法正常加载所需的Jersey组件。

以下是分步解决方案:

1. 修复Maven Shade插件的资源合并配置

Jersey通过META-INF/services目录下的SPI文件加载服务实现,Shade插件默认会用最后一个JAR中的同名文件覆盖之前的,导致部分服务条目丢失。你需要添加ServicesResourceTransformer来合并这些文件:

在你的pom.xml中更新Shade插件配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.4.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.yourpackage.YourMainClass</mainClass>
                    </transformer>
                    <!-- 合并所有META-INF/services下的SPI文件 -->
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <!-- 合并Jersey的版本信息文件,避免冲突 -->
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/jersey-module-version</resource>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

2. 优化Jetty中Jersey Servlet的注册方式

你当前通过initParameter指定provider类名的方式,在打包后可能出现类路径查找问题。改用ResourceConfig直接注册端点类会更可靠:

// 配置第一个Jersey应用
ResourceConfig entryResourceConfig = new ResourceConfig();
entryResourceConfig.register(EntryPoint.class);
ServletHolder entryServletHolder = new ServletHolder(new ServletContainer(entryResourceConfig));
entryServletHolder.setInitOrder(0);
context.addServlet(entryServletHolder, "/entry/*");

// 配置第二个Jersey应用
ResourceConfig noEntryResourceConfig = new ResourceConfig();
noEntryResourceConfig.register(NoEntryPoint.class);
ServletHolder noEntryServletHolder = new ServletHolder(new ServletContainer(noEntryResourceConfig));
noEntryServletHolder.setInitOrder(1);
context.addServlet(noEntryServletHolder, "/noentry/*");

这种方式跳过了类名的字符串查找,直接通过代码注册类实例,减少了类路径相关的问题。

3. 启用详细日志定位深层问题

因为你运行JAR时控制台没有报错,大概率是日志配置未生效,无法看到Jersey内部的错误堆栈。添加SLF4J+Logback依赖来开启DEBUG日志:

在pom.xml中添加依赖:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

然后在src/main/resources下创建logback.xml:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 开启Jersey的DEBUG日志 -->
    <logger name="org.glassfish.jersey" level="DEBUG"/>
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

重新打包后运行JAR,就能看到Jersey处理请求时的详细错误信息,方便进一步排查。

为什么Eclipse中运行正常?

Eclipse是直接从项目的类目录和依赖JAR中加载资源,每个依赖的SPI文件都是独立存在的,不会被覆盖;而Shade插件将所有依赖合并到一个JAR中,默认的合并策略会覆盖重复资源,导致Jersey无法找到完整的服务实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:47:42