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

JDK8编译代码在JDK21环境运行报NoClassDefFoundError问题求助

问题解决方案:JDK8编译代码在JDK21运行时找不到java.sql.Driver

问题背景

使用JDK8编译的Jar包在JDK21环境运行时,抛出java.lang.NoClassDefFoundError: java/sql/Driver,根因是java.lang.ClassNotFoundException: java.sql.Driver,堆栈信息如下:

java.lang.NoClassDefFoundError: java/sql/Driver
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1027)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
at com.thunisoft.tas.server.util.ClosableClassLoader.defineClass(ClosableClassLoader.java:105)
at com.thunisoft.tas.server.util.ClosableClassLoader.findClass(ClosableClassLoader.java:52)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
at com.thunisoft.tas.server.module.jdbc.JdbcService.injectDriver(JdbcService.java:628)
at com.thunisoft.tas.server.module.jdbc.JdbcService.doStart(JdbcService.java:83)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
at org.eclipse.jetty.server.Server.start(Server.java:423)
at org.eclipse.jetty.util.component.ContainerLifeCycle.addBean(ContainerLifeCycle.java:384)
at org.eclipse.jetty.util.component.ContainerLifeCycle.addBean(ContainerLifeCycle.java:313)
at com.thunisoft.tas.server.TasManager.doStart(TasManager.java:162)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
at org.eclipse.jetty.server.Server.start(Server.java:423)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
at org.eclipse.jetty.server.Server.doStart(Server.java:387)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.xml.XmlConfiguration.lambda$main$3(XmlConfiguration.java:1931)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:571)
at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1881)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.eclipse.jetty.start.Main.invokeMain(Main.java:218)
at org.eclipse.jetty.start.Main.start(Main.java:491)
at org.eclipse.jetty.start.Main.main(Main.java:77)
at com.thunisoft.tas.start.TasServiceWrapperListener.doStart(TasServiceWrapperListener.java:71)
at com.thunisoft.tas.start.TasServiceWrapperListener.access$000(TasServiceWrapperListener.java:15)
at com.thunisoft.tas.start.TasServiceWrapperListener$1.run(TasServiceWrapperListener.java:46)
at java.base/java.lang.Thread.run(Thread.java:1583)

根因堆栈:

Caused by: java.lang.ClassNotFoundException: java.sql.Driver
at com.thunisoft.tas.server.util.ClosableClassLoader.findClass(ClosableClassLoader.java:57)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
... 34 common frames omitted

问题原因

Java 9及以后引入了模块系统,java.sql.Driver所在的java.sql模块不再默认被所有类加载器自动访问。自定义的ClosableClassLoader没有正确处理模块化环境下的类加载逻辑,无法从系统模块中加载该类;同时JDK8中该类属于核心类库,JDK21中则属于独立模块,直接跨版本运行会出现类路径/模块路径的适配问题。

解决方案

  • 启动时显式添加java.sql模块:在启动Jar包的命令中加入--add-modules java.sql参数,确保JDK21的模块系统将该模块暴露给应用类加载器。例如:
    java --add-modules java.sql -jar your-app.jar
    
  • 修复自定义类加载器逻辑:修改ClosableClassLoader的findClass或loadClass方法,对于java.sql.Driver这类系统核心类,委托给父类加载器(如AppClassLoader)去加载,而不是自己尝试查找。示例逻辑:
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if (name.startsWith("java.sql.") || name.equals("java.sql.Driver")) {
            return getParent().loadClass(name);
        }
        // 原有自定义类加载逻辑
    }
    
  • 更新JDBC驱动版本:使用兼容JDK9+的新版JDBC驱动,比如MySQL Connector/J 8.0+、PostgreSQL Driver 42.2+等。新版驱动支持模块化规范,会通过ServiceLoader自动注册驱动,无需手动加载java.sql.Driver类,避免依赖问题。
  • 移除手动加载Driver的代码:如果代码中存在Class.forName("com.mysql.cj.jdbc.Driver")这类手动加载驱动的代码,可以直接删除。JDBC 4.0及以后的规范中,驱动会自动通过META-INF/services/java.sql.Driver文件注册,不需要显式调用加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 09:42:03