我发现原因是我用
classloader.close()
.
这是错误代码。
错误: java.lang.NoClassDefFoundError:org/postgresql/Driver$1
try (URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {new URL("file:///" + uriPath)}, Thread.currentThread().getContextClassLoader())) {
Class<?> clazz = classLoader.loadClass(driverClassName);
if (clazz.newInstance() instanceof Driver) {
Driver driver = (Driver) clazz.newInstance();
return driver;
}
} catch (Exception e) {
log.error("error");
}
当我不使用 try-with-resource 时,这个错误就消失了。 正确的代码:
try {
ClassLoader ctxClassloader = Thread.currentThread().getContextClassLoader();
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {new URL("file:///" + uriPath)},
ctxClassloader);
Class<?> clazz = classLoader.loadClass(driverClassName);
if (clazz.newInstance() instanceof Driver) {
Driver driver = (Driver) clazz.newInstance();
return driver;
}
} catch (Exception e) {
log.error("error");
}
这就是我使用驱动程序的方式。我在springboot中使用它。
Driver driver = getDriver(xx);
JdbcTemplate jdbcTemplate = new JdbcTemplate(new SimpleDriverDataSource(driver, "xx", properties));
String s = jdbcTemplate.queryForObject("select VERSION()", String.class); //error happens
谁能告诉我原因吗?为什么使用
classloader.close()
后,显示java.lang.NoClassDefFoundError
。谢谢你! :)
URLClassLoader.close()
的 JavaDoc 描述了它的功能:
关闭这个
,这样它就不能再用于加载这个加载器定义的新类或资源。委托层次结构中此加载器的任何父代定义的类和资源仍然可以访问。此外,任何已经加载的类或资源仍然可以访问。URLClassLoader
当您通过类加载器创建
Driver
的实例时,JVM 将仅加载加载驱动程序和实例化驱动程序所需的最少数量的类。
仅在(例如)使用您的驱动程序打开 JDBC 连接时才需要的其他类尚未加载 - 它们在需要时加载(即打开 JDBC 连接时)。
当您在实例化驱动程序后关闭类加载器时,它不能再用于加载该类,因此您会看到
java.lang.NoClassDefFoundError
:您的类加载器无法加载该类,因为类加载器已关闭,并且它的父类加载器没有那个班级。