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 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"

jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.net.URLClassLoa_第1张图片

 ok,大功告成。

你可能感兴趣的:(linux脚本语言,web开发,java开发,java,jar,动态加载类)