URLClassLoader加载多版本JAR遇UnsupportedClassVersionError问题排查
问题描述
我使用URLClassLoader为基于OpenJDK15编译的应用动态加载JDBC驱动,因部分驱动存在兼容问题无法升级JDK版本。其中一款驱动依赖的truffle-api-22.2.0.jar包含META-INF/versions/11和17两个版本目录,加载该JAR时抛出如下异常:
java.lang.UnsupportedClassVersionError: META-INF/versions/17/module-info has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 59.0 java.lang.UnsupportedClassVersionError: META-INF/versions/17/module-info has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 59.0 at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016) at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151) at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:825) at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:723) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:646) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:604) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:576) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) at com.wisecoders.dbs.dbms.driver.model.a.a(DriverClassLoader.java:132) at com.wisecoders.dbs.dbms.driver.model.a.b(DriverClassLoader.java:110) at com.wisecoders.dbs.dbms.driver.model.a.a(DriverClassLoader.java:88) at com.wisecoders.dbs.dbms.driver.model.a.a(DriverClassLoader.java:66) at com.wisecoders.dbs.dbms.driver.model.a.<init>(DriverClassLoader.java:34)
加载代码如下:
urlClassLoader = new URLClassLoader( urlsArray, OneClassFromMyCode.class.getClassLoader() ); urlClassLoader.loadClass( className );
按URLClassLoader文档说明,它应该支持多版本JAR,请问问题原因可能是什么?
问题原因分析
- 多版本JAR模块信息处理逻辑缺陷:JDK 9+的多版本JAR规范要求,
META-INF/versions/N下的module-info.class仅在运行时JDK版本≥N时才会被加载,但OpenJDK15(类文件版本59.0)却尝试加载了JDK17(类文件版本61.0)对应的module-info。本质是URLClassLoader在处理模块信息时,未正确过滤高于当前运行时版本的module-info文件,错误地将所有版本目录下的该文件纳入加载流程。 - 类加载委托机制干扰:创建
URLClassLoader时指定了应用类加载器作为父加载器,当加载truffle-api相关资源时,父加载器(AppClassLoader)会优先执行类查找逻辑,而AppClassLoader对多版本JAR的处理存在缺陷,误读取了高版本目录下的module-info文件。 - 目标JAR的多版本格式不规范:
truffle-api-22.2.0.jar的版本目录结构可能不符合规范,比如META-INF/versions/17下的module-info未正确关联仅JDK17及以上才需加载的类,导致低版本JDK扫描JAR时误触发了该文件的加载操作。
内容的提问来源于stack exchange,提问作者DbSchema
相关产品推荐
相关产品推荐

