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

使用jlink构建Docker镜像后Spring Boot应用JwtDecoder初始化异常

问题

Spring Boot应用在Eclipse中及直接运行Jar文件时均正常,但通过jlink构建Docker镜像后,应用能正常启动,但调用接口时抛出JwtDecoderInitializationException异常。

异常日志

2023-11-14 05:48:45.584   [http-nio-8080-exec-2] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet].log(175)               : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.security.oauth2.jwt.JwtDecoderInitializationException: Failed to lazily resolve the supplied JwtDecoder instance
        at org.springframework.security.oauth2.jwt.SupplierJwtDecoder.wrapException(SupplierJwtDecoder.java:53)
        at org.springframework.security.oauth2.jwt.SupplierJwtDecoder.lambda$new$0(SupplierJwtDecoder.java:39)
        at org.springframework.util.function.SingletonSupplier.get(SingletonSupplier.java:97)
        at org.springframework.security.oauth2.jwt.SupplierJwtDecoder.decode(SupplierJwtDecoder.java:49)
        at org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.getJwt(JwtAuthenticationProvider.java:99)
        at org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.authenticate(JwtAuthenticationProvider.java:88)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
        at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:137)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)


2023-11-14 05:48:45.684   [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet].log(175)               : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.security.oauth2.jwt.JwtDecoderInitializationException: Failed to lazily resolve the supplied JwtDecoder instance
        at org.springframework.security.oauth2.jwt.SupplierJwtDecoder.wrapException(SupplierJwtDecoder.java:53)

构建镜像使用的Dockerfile

FROM amazoncorretto:21-alpine3.17-jdk as builder

ARG ARTIFACTORY_USER
ARG ARTIFACTORY_TOKEN

WORKDIR /app

COPY . /app

RUN ./gradlew build -Partifactory.password=${ARTIFACTORY_TOKEN} -Partifactory.username=${ARTIFACTORY_USER}
RUN ./gradlew copyDependencies 

RUN jdeps --ignore-missing-deps -q \
    --multi-release 21 --print-module-deps \
    --class-path="build/lib/*" \
    --module-path="build/lib/*" build/libs/user-network-dev-04.10.2023.01-plain.jar > jre-deps.info

RUN jlink --verbose \
    --compress 2 \
    --strip-java-debug-attributes \
    --no-header-files \
    --no-man-pages \
    --output jre \
    --add-modules $(cat jre-deps.info)

FROM alpine:latest
WORKDIR /application

COPY --from=builder /app/jre /jre

COPY --from=builder /app/build/lib/* lib/

COPY --from=builder /app/build/libs/user-network-dev-04.10.2023.01-plain.jar app.jar

ENTRYPOINT ["/jre/bin/java", "-jar", "app.jar"]

原因分析与解决方案

核心原因

jdeps命令中使用的--ignore-missing-deps参数会忽略缺失的模块依赖,导致jlink构建的自定义JRE中缺少Spring Security OAuth2 JWT解码必需的关键模块(如证书解析、加密算法相关的java.naming、jdk.crypto.ec等),进而触发懒加载初始化失败。

解决步骤

  1. 移除jdeps的忽略参数
    删除--ignore-missing-deps,让jdeps完整分析依赖,避免掩盖缺失问题:

    RUN jdeps --multi-release 21 --print-module-deps \
        --class-path="build/lib/*" \
        --module-path="build/lib/*" build/libs/user-network-dev-04.10.2023.01-plain.jar > jre-deps.info
    
  2. 手动补充JWT必需模块
    如果jdeps分析仍遗漏关键模块,可在jlink命令中直接添加:

    RUN jlink --verbose \
        --compress 2 \
        --strip-java-debug-attributes \
        --no-header-files \
        --no-man-pages \
        --output jre \
        --add-modules $(cat jre-deps.info),java.naming,jdk.crypto.ec,java.xml.crypto
    

    这些模块是JWT验证、证书解析过程的核心依赖。

  3. 验证自定义JRE完整性
    镜像构建完成后,进入容器执行/jre/bin/java --list-modules,确认上述补充模块已包含。

  4. 替代方案:使用Spring Boot官方分层镜像
    若手动jlink配置繁琐,可直接用Spring Boot提供的镜像构建能力,自动处理依赖与JRE:

    FROM amazoncorretto:21-alpine3.17-jdk as builder
    WORKDIR /app
    COPY . .
    RUN ./gradlew bootBuildImage --image-name=your-image-name
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 00:20:33