java - 在非默认类加载器下运行本地集群

标签 java classloader apache-storm

来自网络类加载器的本地集群

我正在尝试从 Web 容器运行本地集群(是的,它仅用于开发和测试目的)并且在类加载器方面遇到困难。

直接方法

当我做到这一点时,很容易 recommended方式,

ILocalCluster localCluster = new LocalCluster();
localCluster.submitTopology(topologyName, stormConf, topology);

我得到奖励

Async loop died!: java.lang.ClassCastException: my.company.storm.bolt.SomeFilteringBolt cannot be cast to org.apache.storm.task.IBolt
    at org.apache.storm.daemon.executor$fn__7953$fn__7966.invoke(executor.clj:787)
    at org.apache.storm.util$async_loop$fn__625.invoke(util.clj:482)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.lang.Thread.run(Thread.java:745)

这是因为用于加载和实例化 StormTopology 的类加载器是 Jetty WebAppClassLoader 的实例,但是由 LocalCluster 生成的(子)进程。 submitTopology() 显然使用了系统类加载器。我通过在 SomeFilteringBolt 的静态 block 中记录类加载器来确认这一点 - 该类确实被加载了两次,并且来自 WebAppCL 的 bolt 显然不能稍后转换为系统类加载器上的 bolt 。

预期行为

现在,这让我感到惊讶,因为我认为 Storm 会序列化 StormTopology 实例,在本地“发送”它,反序列化并运行它。但是,如果这样做,它肯定会起作用。相反,它似乎直接使用提供的 StormTopology 实例,这在不同的类加载器下是有问题的。

从那以后我尝试了什么

我尝试将它们设置为 true 以强制 Storm 在本地序列化我的拓扑。没有变化。

我尝试在系统类加载器下运行 LocalCluster:

ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader();
try {
    Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());

    Config topologyConf = createTopologyConfig();
    Map<String, Object> stormConf = createStormConfig(topologyConf);
    StormTopology topology = createTopology(topologyConf);

    ILocalCluster localCluster = new LocalCluster();
    localCluster.submitTopology(topologyName, stormConf, topology);
} finally {
    Thread.currentThread().setContextClassLoader(originalClassloader);
}

这实际上让我更进一步:

Thread  died: java.lang.ExceptionInInitializerError
    at clojure.core__init.__init0(Unknown Source)
    at clojure.core__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at clojure.lang.RT.classForName(RT.java:2154)
    at clojure.lang.RT.classForName(RT.java:2163)
    at clojure.lang.RT.loadClassForName(RT.java:2182)
    at clojure.lang.RT.load(RT.java:436)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.lang.RT.doInit(RT.java:454)
    at clojure.lang.RT.<clinit>(RT.java:330)
    at clojure.lang.Namespace.<init>(Namespace.java:34)
    at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
    at clojure.lang.Var.internPrivate(Var.java:151)
    at org.apache.storm.LocalCluster.<clinit>(Unknown Source)
    at my.company.storm.LocalTopologyRunner.startTopology(LocalTopologyRunner.java:146)
    ... 10 more
Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/refer
    at clojure.lang.Var$Unbound.throwArity(Var.java:43)
    at clojure.lang.AFn.invoke(AFn.java:32)
    at clojure.lang.Var.invoke(Var.java:379)
    at clojure.lang.RT.doInit(RT.java:467)
    at clojure.lang.RT.<clinit>(RT.java:330)
    ... 18 more

哇?!

问题

如何从系统类加载器以外的类加载器以本地模式安全地运行 Storm 拓扑?

我在 Apache Storm 1.0.1、Jetty 8.1、Java 8u112 x64、Windows 7 x64 上运行。

最佳答案

根本不是 Storm 专家,但这让我想起了我过去遇到的一个老“身份危机”问题。

尝试两件事:

  • 通过调用 org.eclipse.jetty.webapp.WebAppContext.setParentLoaderPriority(true)

  • 设置系统类加载器的优先级
  • 如果它不起作用,您可以调用方法 org.eclipse.jetty.webapp.WebAppContext.setSystemClassesorg.eclipse.jetty.webapp.WebAppContext。 addSystemClass 以控制哪些类被视为 webapp 域内的系统类。

在加载它们之前(在 webapp 初始化期间)为整个 storm 包执行此操作(它允许像“org.apache.storm.”这样的通配符)。

值得一试!祝你好运。

关于java - 在非默认类加载器下运行本地集群,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41745602/

相关文章:

java:是否有一个框架允许动态加载和卸载jar(但不是osgi)?

java - 如何将tomcat服务器的请求重定向到另一个tomcat服务器

java - HibernatePersistenceProvider.createEntityManagerFactory() 方法的 JBoss AS7 LinkageError

java - 解决gradle依赖关系期间的Eclipse错误

java - Spark 无法从 webjar 加载静态文件

java - "explore"是否有可能在运行时通过反射在另一个对象中定义哪些对象?

java - HBase 表设计用于维护每个来源的每小时访客数量

java - Apache Storm - Storm-starter 上的 ClassNotFoundException

apache-storm - 什么会导致zookeeper Client session超时

java - 无法在项目 inv-project 上执行目标 org.codehaus.mojo :rpm-maven-plugin:2. 0.1:rpm (default-cli)