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版本即可

相关推荐
Olrookie16 分钟前
若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
java·前端·笔记·后端·学习·vue·ruoyi
LucianaiB32 分钟前
招聘可以AI面试,那么我制作了一个AI面试教练不过分吧
后端
无奈何杨1 小时前
CoolGuard更新,ip2region升级、名单增加过期时间
后端
摇滚侠2 小时前
Spring Boot 3零基础教程,WEB 开发 自定义静态资源目录 笔记31
spring boot·笔记·后端·spring
Anthony_49262 小时前
逻辑清晰地梳理Golang Context
后端·go
Github项目推荐2 小时前
你的错误处理一团糟-是时候修复它了-🛠️
前端·后端
进击的圆儿2 小时前
高并发内存池项目开发记录01
后端
左灯右行的爱情2 小时前
4-Spring SPI机制解读
java·后端·spring
用户68545375977693 小时前
🎯 Class文件结构大揭秘:打开Java的"身份证" 🪪
后端
sp423 小时前
一套清晰、简洁的 Java AES/DES/RSA 加密解密 API
java·后端