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

如何在Java 17 Gradle项目中依赖Java 21编译的类

HelloWorld/
  ├── core
  └── api/
    ├── stable
    └── preview

HelloWorld是Java 17项目,受多数客户限制无法升级Java版本。
api/preview模块依赖Java 21外部库,其build.gradle配置如下:

java {
    toolchain.languageVersion = JavaLanguageVersion.of(21) // 依赖Java 21外部库
}

core模块的build.gradle配置如下:

dependencies {
    compileOnly(":api:stable")
    compileOnly(":api:preview") // 该模块基于Java 21
}
java {
    toolchain.languageVersion = JavaLanguageVersion.of(17) // 该模块基于Java 17
}

需求场景:

  • 客户端为Win10时,使用基于JDK 17的WinUtil 3
  • 客户端为Win11时,使用基于JDK 21的WinUtil 4
实现方案

1. 确保api/preview模块输出兼容Java 17的字节码

api/preview用JDK21编译,但可配置生成Java17兼容的字节码,让core模块能正常引用。修改api/preview的build.gradle:

java {
    toolchain.languageVersion = JavaLanguageVersion.of(21)
    // 指定兼容Java17的字节码版本
    targetCompatibility = JavaVersion.VERSION_17
    sourceCompatibility = JavaVersion.VERSION_17
    // 添加release参数,确保不引用JDK21独有API(若必须用独有API,跳过此步,改用反射/SPI隔离)
    tasks.withType(JavaCompile) {
        options.compilerArgs.add('--release')
        options.compilerArgs.add('17')
    }
}

注意:如果api/preview必须用JDK21独有API(如虚拟线程新特性),此方法失效,需用反射或SPI隔离这类代码。

2. 基于客户端系统动态切换依赖

方式一:打包阶段通过Gradle参数区分

修改core模块的build.gradle,根据系统属性动态引入依赖:

dependencies {
    compileOnly(":api:stable")
    // 依据外部传入的参数决定是否引入preview模块
    if (project.hasProperty('enablePreviewApi')) {
        compileOnly(":api:preview")
    }
}

打包时通过命令行指定:

  • Win10版本:./gradlew build -PenablePreviewApi=false
  • Win11版本:./gradlew build -PenablePreviewApi=true

方式二:运行时通过SPI动态加载

若需在同一包中自动适配客户端系统,用SPI机制实现:

  1. 在api/stable模块定义统一接口:
public interface WinUtil {
    void execute();
}
  1. 编写实现类:
    • api/stable中实现WinUtil3(兼容JDK17)
    • api/preview中实现WinUtil4(基于JDK21)
  2. 配置SPI文件:
    • 在api/stable的src/main/resources/META-INF/services/com.example.WinUtil中写入com.example.WinUtil3
    • 在api/preview的src/main/resources/META-INF/services/com.example.WinUtil中写入com.example.WinUtil4
  3. core模块中编写加载逻辑:
import java.util.ServiceLoader;

public class WinUtilFactory {
    public static WinUtil getInstance() {
        String osVersion = System.getProperty("os.version");
        // Win11版本号起始为10.0.22000及以上
        boolean isWin11 = osVersion.startsWith("10.0.") && Integer.parseInt(osVersion.substring(5)) >= 22000;
        
        ServiceLoader<WinUtil> loader = ServiceLoader.load(WinUtil.class);
        for (WinUtil util : loader) {
            if (isWin11 && util.getClass().getSimpleName().equals("WinUtil4")) {
                return util;
            } else if (!isWin11 && util.getClass().getSimpleName().equals("WinUtil3")) {
                return util;
            }
        }
        return loader.findFirst().orElseThrow(() -> new RuntimeException("未找到可用WinUtil实现"));
    }
}

同时调整core模块依赖:

dependencies {
    implementation(":api:stable")
    // 将preview设为可选依赖,运行时按需加载
    optional(":api:preview")
}

3. 处理运行时JDK版本匹配问题

如果WinUtil4必须在JDK21环境运行,需保证Win11客户端使用JDK21,Win10使用JDK17:

  • 提供不同启动脚本:Win10用JDK17的java命令启动,Win11用JDK21的java命令启动
  • 在代码中检测JDK版本,若Win11环境下JDK版本低于21,抛出提示或自动降级使用WinUtil3

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:12:38