jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.net.URLClassLoa
今天遇到了个奇怪的问题,部署到新环境后,动态加载类的功能报错。Exception in thread "main" java.lang.RuntimeException: java.lang.ClassCastException: jdk.internal.loader.ClassLoaders$AppClassLoader (in module: java.base) cannot be cas
·
今天遇到了个奇怪的问题,部署到新环境后,动态加载类的功能报错。
Exception in thread "main" java.lang.RuntimeException: java.lang.ClassCastException: jdk.internal.loader.ClassLoaders$AppClassLoader (in module: java.base) cannot be cast to java.net.URLClassLoader (in module: java.base)
后来发现新环境的jdk的版本是9。于是查了下资料,得出结论:Java9之后,应用程序和扩展类都不再是 java.net.URLClassLoader 的实例。
于是修改了下加载动态类的代码,这是之前的代码
File jarFile = new File(jarPath);//jarPath是jar路径
// 从URLClassLoader类中获取类所在文件夹的方法,jar也可以认为是一个文件夹
Method method = null;
try {
method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
} catch (NoSuchMethodException | SecurityException e1) {
e1.printStackTrace();
}
// 获取方法的访问权限以便写回
boolean accessible = method.isAccessible();
try {
method.setAccessible(true);
// 获取系统类加载器
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
URL url = jarFile.toURI().toURL();
method.invoke(classLoader, url);
} catch (Exception e) {
e.printStackTrace();
} finally {
method.setAccessible(accessible);
}
下面是修改后的代码
File jarFile = new File(jarPath);
ClassLoader classLoader = null;
URL url = null;
try {
// 获取系统类加载器
classLoader = ClassLoader.getSystemClassLoader();
url = jarFile.toURI().toURL();
}catch (Exception e){
e.printStackTrace();
}finally {
}
if (classLoader instanceof URLClassLoader) {
System.out.println("DEB: classLoader instanceof URLClassLoader");
URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(sysloader, url);
} catch (Exception var5) {
var5.printStackTrace();
throw new IllegalStateException(var5.getMessage(), var5);
}
} else {
try {
Field field = classLoader.getClass().getDeclaredField("ucp");
field.setAccessible(true);
Object ucp = field.get(classLoader);
System.out.println("DEB: invoke method!");
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(ucp, url);
} catch (Exception exception) {
exception.printStackTrace();
throw new IllegalStateException(exception.getMessage(), exception);
}
}
改完之后发现请求还是会报错,报错信息如下
java.lang.reflect.InaccessibleObjectException: Unable to make field final jdk.internal.loader.URLClassPath jdk.internal.loader.ClassLoaders$AppClassLoader.ucp accessible: module java.base does not "opens jdk.internal.loader" to unnamed module @6b143ee9
改原因是 Java 9+ 以上版本中不允许使用动态加载类,因为想要使用就需要加两个参数给虚拟机,
重点线-----------------------上面是参考原作者的内容,下面的解决方式是自己实际情况,仅供参考
我使用的是tomcat启动方式,需要修改tomcat bin目录下的catalina.sh文件,加入这两行脚本
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED"
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-opens=jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED"
ok,大功告成。
更多推荐
所有评论(0)