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

如何将jcharset集成到Spring Boot Fat Jar并解决类加载问题?

问题描述

我尝试将jcharset集成到项目中,但数日未能成功。我的环境:

  • Spring Boot Fat Jar
  • Java 17
  • Docker镜像gcr.io/distroless/java17-debian12

该库在本地正常工作,但部署环境中失效,原因是类加载机制差异。Spring Boot的spring-boot-maven-plugin构建的Fat Jar为标准结构。我可以修改Maven构建插件或其他配置,但不确定如何将服务添加到Fat Jar的META-INF/classes目录下。

已尝试以下方法但均无效:

  • 使用java -cp指定该库——无法将其加载到SystemClassLoader
  • 将库jar放入/usr/lib/jvm/java-17-openjdk-arm64/lib/jcharset-2.1.jar——Java 9及以上版本不适用
  • 搭配spring-boot-maven-plugin使用其他Maven插件——无效果
  • 使用Instrumentation API——但似乎需要构建第二个jar
解决方案

核心问题是jcharset需要被SystemClassLoader加载,而Spring Boot Fat Jar默认会把依赖包打包到BOOT-INF/lib下,由自定义类加载器加载,导致字符集服务无法被Java的SPI机制发现。解决思路是把jcharset的内容直接解压到Fat Jar的META-INF/classes目录下,这样就能被SystemClassLoader加载。具体步骤如下:

  1. 添加Maven依赖解压插件
    在pom.xml的<build><plugins>节点中加入maven-dependency-plugin配置,用于将jcharset的类文件和SPI配置解压到项目编译输出目录:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-jcharset</id>
            <phase>process-resources</phase>
            <goals>
                <goal>unpack</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>net.freeutils</groupId>
                        <artifactId>jcharset</artifactId>
                        <version>2.1</version> <!-- 替换为你实际使用的版本 -->
                        <outputDirectory>${project.build.outputDirectory}</outputDirectory>
                        <includes>**/*.class, META-INF/services/**</includes>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

这个配置会在process-resources阶段自动执行,把jcharset的核心文件解压到target/classes目录。

  1. 确认Spring Boot打包包含解压内容
    spring-boot-maven-plugin默认会将target/classes下的所有文件打包到Fat Jar的META-INF/classes目录,无需额外调整插件配置,只要保证解压步骤在打包之前执行即可(Maven默认阶段顺序满足这个要求)。

  2. 验证打包结果
    执行mvn package构建Fat Jar后,可通过jar tf your-app.jar命令查看内部结构:

  • 确认META-INF/services/java.nio.charset.spi.CharsetProvider文件存在,且内容包含net.freeutils.charset.CharsetProviderImpl
  • 确认net/freeutils/charset路径下的类文件位于META-INF/classes目录下
  1. Docker部署
    使用distroless镜像时,直接挂载构建好的Fat Jar启动即可,启动命令保持Spring Boot默认方式:
java -jar your-app.jar
原理说明

Java的SPI机制(如字符集提供者加载)依赖SystemClassLoader读取META-INF/services下的配置并加载实现类。Spring Boot Fat Jar的META-INF/classes目录会被加入SystemClassLoader的类路径,而BOOT-INF/lib下的依赖仅由Spring自定义类加载器加载,因此将jcharset的内容放到META-INF/classes就能让SPI机制正常识别它。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:33:17