Dubbo服务调用JDK版本不兼容如何解决

大家好,这里是小奏 ,觉得文章不错可以关注公众号小奏技术

背景

最近,我们团队在开发一个新服务时,选择了Spring Boot 3 + Dubbo 3 + JDK 17 的技术栈。

项目运行比较顺利,但在Dubbo RPC调用时遇到了一个棘手的问题:其他团队的项目使用的是JDK 11,导致我们的JAR包在他们的环境中运行时出错

报错信息如下

java 复制代码
java: 无法访问 com.xiaozou.rpc.XiaoZouService
  错误的类文件: /Users/xiaozou/Desktop/sofe/java/localRepository/com/xiaozou/1.0.0-SNAPSHOT/xiaozou-1.0.0-SNAPSHOT.jar!/com/xiaozou/rpc/XiaoZouService.class
    类文件具有错误的版本 61.0, 应为 55.0
    请删除该文件或确保该文件位于正确的类路径子目录中

从错误提示中可以看出,JAR 包中的类文件版本为 61.0(对应 JDK 17),而目标环境期望的版本是 55.0(对应 JDK 11)。这引发了版本不兼容的问题

原因分析

Java 源代码(.java 文件)通过 javac 编译成字节码文件(.class 文件)时,会在文件头部写入版本信息。不同 JDK 版本生成的 .class 文件版本不同:

  • Java 8:52.0
  • Java 11:55.0
  • Java 17:61.0

如果要验证我们可以直接使用idea自带的反编译工具直接查看/target/classes下的.class文件

可以看到不同的JDK版本生成的.class文件头部的版本信息是不一样的,idea反编译可以识别出来

我们也可以使用javap命令查看.class文件的版本信息

shell 复制代码
javap -v XiaoZou.class

那么我们就会得到如下字节码信息

java 复制代码
  Last modified 2025年2月26日; size 229 bytes
  SHA-256 checksum e8457714c4513babc6686fd96495e7ad7b65658b143023c8b8185bbacb757eea
  Compiled from "XiaoZou.java"
public interface com.xiaozou.XiaoZou
  minor version: 0
  major version: 55
  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
  this_class: #1                          // com/xiaozou/XiaoZou
  super_class: #3                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 1, attributes: 1

输出中会显示major version: 55,表示该类文件是JDK 11 编译的。

jdk的源码中verify_class_version方法就会对class的版本进行校验

如果class的版本大于当前的版本就会抛出UnsupportedClassVersionError异常

所以高版本JDK编译的类文件在低版本JDK上运行时,低版本JDK会直接编译报错

解决方案

由于我们是dubbo RPC调用发布简单的RPC接口jar给到其他服务调用,除了基本的接口定义,不会使用高版本JDK的特性,所以解决方式相对来说也比较容易。

如果是一些公用sdk就需要针对性发布不同jdk版本的sdk,这里不做讨论

打包出一个低版本的jar

所以第一个解决方案是我们可以打一个低版本的jar给其他低版本的服务使用

我们项目的模块是如下结构

java 复制代码
- xiaozou-service
    - xiaozou-api
    - xiaozou-start

我们在xiaozou-service中配置了全局的打包插件

xml 复制代码
        <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        </properties>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>

指定了sourcetarget的版本为17,所以我们打出来的jar就是JDK 17的版本

但是我们可以在xiaozou-api模块进行覆盖

xiaozou-apipom.xml添加如下配置

xml 复制代码
    <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    </properties>

这样xiaozou-api打出来的jar版本是JDK 11

低版本服务升级JDK

虽然这是一种解决方案,但升级JDK可能涉及较大的工程量和风险,不太现实。

使用 Multi-Release JAR Files

JDK 9引入了Multi-Release JAR Files特性,允许在一个JAR文件中包含多个版本的类文件。

虽然这可以解决版本兼容问题,但配置较为复杂,不适合本场景。

总结

JDK 版本不兼容是Dubbo服务调用中常见的问题,特别是在跨团队协作时。

解决这一问题的最简单方法是打包一个低版本的JAR包,以确保兼容性。

如果不想折腾,保持团队之间JDK版本即可

相关推荐
sg_knight2 小时前
从 Spring Boot 2 升级到 Spring Boot 3 的终极指南
java·spring boot·后端·springcloud
叉烧钵钵鸡3 小时前
【Spring详解六】容器的功能扩展-ApplicationContext
java·开发语言·后端·spring
闲猫3 小时前
go 初印象 开发,并发比java快,且具有C的性能
开发语言·后端·golang
老赵骑摩托4 小时前
Go语言中的信号量:原理与实践指南
开发语言·后端·golang
2501_903238654 小时前
Spring Boot中@EnableAutoConfiguration的魔法与实例解析
java·spring boot·后端·个人开发
钢板兽5 小时前
Java后端面试八股文:系统化学习指南,告别零散知识点
java·linux·jvm·redis·后端·mysql·面试
雪碧聊技术5 小时前
解决后端跨域问题
后端·跨域问题
AskHarries5 小时前
AWS S3 如何设置公开访问权限?
后端·aws
硬件人某某某5 小时前
django校园互助平台~源码
后端·python·django·校园互助