【发布时间】:2017-09-09 17:39:40
【问题描述】:
我遇到了 Java 类加载器的奇怪行为:
假设我向集群提交了一个 Apache Spark jar,其中包含 HiveServer2 的扩展:
package org.apache.hive.service.server;
public class MyOP2 extends HiveServer2.ServerOptionsProcessor(
String var) {
...
HiveServer2.ServerOptionsProcessor 类已经预加载到集群上(作为 Spark 依赖项),但被声明为包私有。
package org.apache.hive.service.server;
public class HiveServer2 extends CompositeService {
...
static interface ServerOptionsExecutor {
...
}
}
这个类在集群建立时首先加载到 JVM 中。然后我的类(在另一个 jar 中)在我的应用程序提交时由同一个 JVM 加载。
此时我收到以下错误:
线程“主”java.lang.IllegalAccessError 中的异常:类 org.apache.hive.service.server.DPServerOptionsProcessor 无法访问 它的超类 org.apache.hive.service.server.HiveServer2$ServerOptionsProcessor 位于 java.lang.ClassLoader.defineClass1(本机方法)在 java.lang.ClassLoader.defineClass(ClassLoader.java:763) 在 java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 在 java.net.URLClassLoader.defineClass(URLClassLoader.java:467) 在 java.net.URLClassLoader.access$100(URLClassLoader.java:73) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:368) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:362) 在 java.security.AccessController.doPrivileged(Native Method) 在 java.net.URLClassLoader.findClass(URLClassLoader.java:361) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:424) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 org.apache.spark.sql.hive.thriftserver.DPHiveThriftServer2$.main(DPHiveThriftServer2.scala:26) 在 org.apache.spark.sql.hive.thriftserver.DPHiveThriftServer2.main(DPHiveThriftServer2.scala) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:731) 在 org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:181) 在 org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:206) 在 org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:121) 在 org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
我的印象是包私有类可以被同一个包中的任何其他类访问。而且我已经仔细检查了 Spark 罐子中的清单文件,它们都没有将 org.apache.hive.service.server 声明为密封包。那么为什么 JVM 类加载器给了我这个错误呢? JVM 使用什么条件触发异常?
【问题讨论】:
-
你能检查一下哪些类加载器加载了这两个类
-
从堆栈跟踪,似乎是普通的旧 URLClassLoader。
-
它们是同一个类加载器吗?
-
不确定,但第二个类加载器(引发错误的那个)肯定可以访问超类和子类
标签: java classloader package-private