分享

storm-starter在Intellij IDEA IDE下调试分析classNot found【推荐】

yuwenge 发表于 2015-7-10 16:35:31 [显示全部楼层] 只看大图 回帖奖励 阅读模式 关闭右栏 3 71469


问题导读

1.本文遇到问题是如何分析的?
2.classNot found的原因是什么?
3.如何解决classNot found?







背景
最近收到这样一个问题:

Storm处理消息时会根据Topology生成一棵消息树,Storm如何跟踪每个消息、如何保证消息不丢失以及如何实现重发消息机制?


虽已回复,但心想还是看下storm这块的源码吧.那看静态多不爽啊,那总得调试吧,好吧,造个本地环境来调吧。

先看看maven的build过不过:


[mw_shl_code=bash,true]mvn -f pom.xml clean install[/mw_shl_code]

搞定storm的编译打包,接着是storm-starter的编译打包,一切很顺利啊,跑一下看看:
[mw_shl_code=bash,true]${STORM_HOME}/bin/storm jar ${STORM_JAR} ${STORM_STARTER_JAR} storm.starter.WordCountTopology[/mw_shl_code]

顺利出结果了,不就是个hello world嘛!

接着造本地环境吧,将storm-starter的源码按maven方式导入Intellij IDEA,注意,从这时候悲催就开始了。







导入IDE后,兴致勃勃的点了F5,然后:
1.png
这尼玛,说好不打脸的!
看了又看依赖“都合适”啊,ClassPath“都合适”啊,否则编译不通过啊,为毛跑!不!起!来!
这同样的操作,在eclipse里妥妥的啊,各种能跑啊,为毛在Intellij IDEA里出错了呢?


异常是如何产生的
好吧,既然打脸了,又是知名IDE的粉丝,坚决要知耻而后勇的。
那么,看下异常如何产生的吧。
1.png
上面的图,基本概括了异常NoClassDefFound产生的路径。
更细节的异常产生情况如下:
2.png
注意看调用栈:



  • JVM_GetClassDelaredMethods是JVM内方法,在找入口函数main的过程中,此方法被调用。
  • 接着,此方法会调用验证字节码的过程:verify_code。
  • 发现有用到backtype.storm.topology.IRichBolt接口,那么找找这个接口所在的.class文件吧:
    如果我们运行java -cp . xxx,通过-cp或者-classpath参数指定了classpath,那么这个.class就会被找到。然后进入parse的过程。
  • 悲催的是,IDEA的运行或者调试命令f5->run,没有将backtype/storm/topology/IRichBolt所在的jar包storm-core.jar加入classpath,这都是后话了...


那么,既然有个找*.class的过程,这个过程如下:
3.png
对上图做一点简要说明:



  • 执行java -cp . $mainClass .
  • java程序(这里指java这个程序本身)的入口函数main,会创建虚拟机JVM实例,过程中会初始化JVM本地ClassLoader.
  • 在JVM寻找.class文件时,调用ClassLoader::load_classfile方法,从jar包、zip包、目录中寻找指定的.class文件 .
  • 本文中,木有找到backtype/storm/topology/IRichBolt.class,所以会置一个延时异常__pending_exception,这个异常关联了这个类(接口)、文件名、异常的类型(NoClassDefFound),那这个异常什么时候处理呢?后文再说.


    看下这个异常的内容:
    4.png



异常是如何处理的
好了,异常的产生清楚了,还有个问题,那个__pending_exception是何时被处理呢?
看下图:
5.png
对上图做下简要说明:


  • 执行java -cp . $mainClass .
  • java程序的入口函数main,在层层初始化的过程中,会调用到LoadMainClass函数, 结合本文的第一幅图就可以知道,这个函数最终会制造那个NoClassDefFound的异常__pending_exception,然后返回的是一个空的mainClass.
  • 紧跟着LoadMainClass函数,是一个CHECK_EXCEPTION_NULL_LEAVE的宏,这个宏展开后,会处理上面制造的那个异常,然后,打印异常信息。这里就是那个被打脸的异常了。


为什么被打了脸
这里,异常产生的本质和异常处理,清楚了。
简单的概括下就是:


[mw_shl_code=bash,true]  /* 伪代码 */
   main /* java这个程序的main */
   -> createJVM() /* 创建JVM */
   -> loadMainClass() /* 加载我们指定的$mainClass文件,这是个class文件 */
   -> findMethod("main") /* 在$mainClass中找main方法,java写的程序的main */
   -> getMethodFromJVM() /* 没缓存,问JVM要 */
   -> classLoader.loadFromFile() /* 在classpath中找.class文件 */
   -> 没找到,置异常NoClassDefFound.[/mw_shl_code]

但是,Intellij IDEA为何在运行时不将storm-core.jar包含进classpath呢?
换句话说:为啥被打脸??
6.png
打脸的理由很简单:
  • F5->run,先make/compile/build,再运行.
  • 依赖的scope设为了provided,此设置仅在编译阶段将依赖的jar包加入classpath,在运行阶段,不会将jar包加入classpath.
解决的方法也非常简单:

[mw_shl_code=bash,true]如果不是通过mvn来运行,而是在IDE下调试/运行,赶紧将依赖的jar包的scope选为compile吧,妥妥的不会被打脸![/mw_shl_code]

看下是不是妥妥的呢?
7.png





已有(3)人评论

跳转到指定楼层
zhenmie365 发表于 2015-9-6 17:24:23
你好楼主,我也遇到类似问题。不过我是
“Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang/builder/HashCodeBuilder”
我是在mavenrepository上下载storm-core的jar包,然后install在本地maven库,再在Eclipse上用这个本地依赖包。而且还按楼主你的提示在pom里的依赖设置了<scope>provided</scope>一样出现找不到的情况。错误代码如下:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang/builder/HashCodeBuilder
        at backtype.storm.generated.GlobalStreamId.hashCode(GlobalStreamId.java:288)
        at java.util.HashMap.hash(HashMap.java:362)
        at java.util.HashMap.put(HashMap.java:492)
        at backtype.storm.generated.ComponentCommon.put_to_inputs(ComponentCommon.java:219)
        at backtype.storm.topology.TopologyBuilder$BoltGetter.grouping(TopologyBuilder.java:329)
        at backtype.storm.topology.TopologyBuilder$BoltGetter.shuffleGrouping(TopologyBuilder.java:293)
        at backtype.storm.topology.TopologyBuilder$BoltGetter.shuffleGrouping(TopologyBuilder.java:289)
        at backtype.storm.topology.TopologyBuilder$BoltGetter.shuffleGrouping(TopologyBuilder.java:264)
        at topology.WordCountTopology.main(WordCountTopology.java:34)
我发现GlobalStreamId.class里import的包系“org.apache.commons.lang.builder.HashCodeBuilder”,而common.lang的官网里说现在用的是long3,可以向下兼容的。但就是会出现错误。请求帮助!!
回复

使用道具 举报

desehawk 发表于 2015-9-6 19:37:11
zhenmie365 发表于 2015-9-6 17:24
你好楼主,我也遇到类似问题。不过我是
“Exception in thread "main" java.lang.NoClassDefFoundError: o ...

是不是搞反了

改成compile 试试
上面是不让改成provided
回复

使用道具 举报

zhenmie365 发表于 2015-9-7 09:02:32
desehawk 发表于 2015-9-6 19:37
是不是搞反了

改成compile 试试

试过用provided都不行。
后来down了《Storm分布式实时计算模式》源码下来看,发现需要手动依赖lang包。因为本地已经库已经有lang包,所以直接在pom加依赖commons-lang 就是了,问题解决。
我觉得,可以这样说,最根本原因是国内网络要自动下载org.apache.storm的storm包实在太慢,无奈唯有去下载国内网站的strom-api包,但因为api包不是全套依赖,所以有很多其他的依赖包都需要自己手动添加依赖。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条