现象
java.lang.reflect.InaccessibleObjectException
在jdk1.8下可以正常运行。切换成jdk11之后,运行时报如下的异常:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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 @bd2f5a9
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:176)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:170)
at com.kutesmart.etl.util.JarLoaderUtil.initAddMethod(JarLoaderUtil.java:24)
at com.kutesmart.etl.util.JarLoaderUtil.<clinit>(JarLoaderUtil.java:18)
at com.kutesmart.etl.service.DataxService.getConnection(DataxService.java:358)
at com.kutesmart.etl.service.DataxService.createTable(DataxService.java:273)
at com.kutesmart.etl.service.DataxService.buildJson(DataxService.java:166)
at com.kutesmart.etl.manager.ExecTimeTaskManage.execute(ExecTimeTaskManage.java:90)
at com.kutesmart.etl.manager.ExecTimeTaskManage.exec2(ExecTimeTaskManage.java:49)
at com.kutesmart.etl.manager.ExecTimeTaskManage.xxlJob(ExecTimeTaskManage.java:246)
at com.kutesmart.etl.service.TaskJob.taskHandler(TaskJob.java:41)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.xxl.job.core.handler.impl.MethodJobHandler.execute(MethodJobHandler.java:31)
at com.xxl.job.core.thread.JobThread$1.call(JobThread.java:143)
at com.xxl.job.core.thread.JobThread$1.call(JobThread.java:136)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.lang.Thread.run(Thread.java:834)
|
原因
参考链接:https://learn.microsoft.com/zh-cn/java/openjdk/transition-from-java-8-to-java-11#classloader-cautions
在Java8中,可以将系统类加载程序强制转换为URLClassLoader。这通常有需要在运行时将类注入到classpath的应用程序和库完成。类加载程序层次结构在Java11中已更改。系统类加载程序(也称为应用程序类加载程序)现在是一个内部类。强制转换为URLClassLoader会在运行时引发ClassCastException。Java11无法通过API在运行时动态增强classpath,但可以通过反射来实现这一点,他会显示有关如何使用内部API的显著警告。
在Java11中,启动类加载程序只加载核心模块。如果创建一个具有null父项的类加载程序,则他可能找不到全部平台类。
在Java11中,需要在此类情况下传递ClassLoader.getPlatformClassLoader()而不是null作为父类加载程序。
解决
添加启动参数,在运行Java应用程序时,添加以下启动参数:
1
|
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
|
由于我们的程序是用k8s部署启动的,所以在deployment中的command修改为以下内容:
1
|
command: ["java", "--add-opens", "java.base/jdk.internal.loader=ALL-UNNAMED", "-jar", "/opt/cnbl-etl-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=prod"]
|