跳到主要内容

Hana 驱动加载问题

问题背景

在适配 SAP Hana 数据源时,使用了 Cobble 提供的类加载机制来加载 JDBC 驱动。然而,在 JDK1.8 环境下加载 Hana Driver 会抛出 java.lang.NoClassDefFoundError: Could not initialize class com.sap.db.jdbc.Driver,而在更高版本 JDK(如 11/17)上则不会出现该问题。

问题现象

在 JDK1.8 中,运行时加载 Hana Driver 时出现异常:

java.lang.NoClassDefFoundError: Could not initialize class com.sap.db.jdbc.Driver

需要注意两个点:

  1. 异常发生在运行期,而编译期没有问题,说明 Jar 包已成功加载。
  2. 问题仅出现在 JDK1.8,JDK11/17 正常,说明与不同版本的 JVM 类加载机制有关。

根据 官方文档,该错误表示 JVM 或 ClassLoader 在运行时试图加载类定义时未找到定义,尽管在编译期是存在的。

问题定位

进一步分析 com.sap.db.jdbc.Driver 的静态代码块。Hana Driver 在静态初始化时会调用 checkJavaVersionMaximum8(),并尝试注册 Driver。异常表明问题出现在其父类 DriverSapDB 的静态初始化阶段。

static {
checkJavaVersionMaximum8();
INSTANCE = new Driver();

try {
DriverManager.registerDriver(INSTANCE);
} catch (SQLException var1) {
System.err.println("Can't register driver: " + INSTANCE.getClass().getCanonicalName() + ": " + var1.getMessage());
}

pptracer = getTracer().getTraceControl();
}

深入 DriverSapDB 静态代码块后发现,问题发生在:

VERSION_INFO = DriverVersionInfo.newInstance(com.sap.db.jdbc.Driver.class.getPackage().toString());

此时 com.sap.db.jdbc.Driver.class.getPackage() 返回 null,导致 toString() 调用抛出空指针异常。也就是说,Driver 类在加载过程中包信息未正确初始化。

完整静态代码块如下:

static {
...
VERSION_INFO = DriverVersionInfo.newInstance(com.sap.db.jdbc.Driver.class.getPackage().toString());
...
}

原因分析

问题根源在于 Cobble 的自定义类加载器。其 InnerClassLoader.findClass 方法在调用 defineClass 时,未显式调用 definePackage,导致 Package 信息未被填充。

class InnerClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
String resource = className.replace(".", "/") + ".class";

try {
InputStream inStream = this.resourceLoader.getResourceAsStream(resource);
if (inStream != null) {
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
ioCopy(inStream, byteOutput);
byte[] bs = byteOutput.toByteArray();
return this.defineClass(className, bs, 0, bs.length);
}
} catch (IOException e2) {
throw new ClassNotFoundException(className, e2);
}

return super.findClass(className);
}
}