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

相关推荐
蜗牛沐雨1 小时前
Rust 中的 `PartialEq` 和 `Eq`:深入解析与应用
开发语言·后端·rust
Python私教1 小时前
Rust快速入门:从零到实战指南
开发语言·后端·rust
秋野酱2 小时前
基于javaweb的SpringBoot爱游旅行平台设计和实现(源码+文档+部署讲解)
java·spring boot·后端
小明.杨2 小时前
Django 中时区的理解
后端·python·django
有梦想的攻城狮2 小时前
spring中的@Async注解详解
java·后端·spring·异步·async注解
qq_12498707532 小时前
原生小程序+springboot+vue医院医患纠纷管理系统的设计与开发(程序+论文+讲解+安装+售后)
java·数据库·spring boot·后端·小程序·毕业设计
lybugproducer3 小时前
浅谈 Redis 数据类型
java·数据库·redis·后端·链表·缓存
焚 城3 小时前
.NET8关于ORM的一次思考
后端·.net
撸猫7915 小时前
HttpSession 的运行原理
前端·后端·cookie·httpsession
嘵奇6 小时前
Spring Boot中HTTP连接池的配置与优化实践
spring boot·后端·http