I found that the reason is I use classloader.close()
.
This is the erroe code.
error: 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");
}
When i don't use try-with-resource, this error has gone. right code:
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");
}
This is how I use the driver. I use it in springboot.
Driver driver = getDriver(xx);
JdbcTemplate jdbcTemplate = new JdbcTemplate(new SimpleDriverDataSource(driver, "xx", properties));
String s = jdbcTemplate.queryForObject("select VERSION()", String.class); //error happens
Could any one tell me the reason? Why after using classloader.close()
, the java.lang.NoClassDefFoundError
shows. Thank you! :)
The JavaDoc for URLClassLoader.close()
describes it function:
Closes this
URLClassLoader
, so that it can no longer be used to load new classes or resources that are defined by this loader. Classes and resources defined by any of this loader's parents in the delegation hierarchy are still accessible. Also, any classes or resources that are already loaded, are still accessible.
When you create an instance of your Driver
through the classloader the JVM will load only the minimum number of classes necessary to load the driver and to instantiate the driver.
Other classes that are only required when (for example) opening a JDBC connection using your driver are not yet loaded - they are loaded when they are required (i.e. when opening a JDBC connection).
When you close the classloader after instantiating the driver it can no longer be used to load that classes and you therefore see the java.lang.NoClassDefFoundError
: your classloader can not load that class because the classloader is closed, and it's parent classloaders don't have that class either.