• dubbo服务provider方打印警告日志,getDeserializer


    2018-09-12 16:16:44 WARN [New I/O worker #1] SerializerFactory.java:652 getDeserializer - Hessian/Burlap: 'com.xxx.xxxBolt$1' is an unknown class in sun.misc.Launcher$AppClassLoader@a2c6f70

    今天下午4点过商品组同事反馈,线上他们那边有个dubbo服务A(provider)打印了很多WARN日志让看看。

    这个日志是在dubbo的hessian-lite模块下SerializerFactory类,Deserializer getDeserializer(String type)方法中打印的:

    看名称大概是获取反序列化类。在服务A中接口方法是能正常调用的,不影响业务。但是该方法调用很频繁,大量这样的WARN日志显然不好。

    其实这个问题之前遇到过,当时是dubbo的provider方接口有升级,方法入参vo有变动,consumer端依赖了provider放的api interface包,没有及时重新构建发布。

    不过看这次日志打印很奇怪,'com.xxx.XxxBolt$1' is an unknown class,XxxBolt是我们这边一个storm拓扑(比如拓扑T)中的一个bolt名称,在该bolt中调用了服务A的一个接口;

    服务A依赖了包B,B下面有个枚举类C;

    该接口方法签名为 Map<枚举类C, Object> 方法名(Long xxId, Set<枚举类C> xxSet);

    检查XxxBolt中调接口的代码,

    调用如下:

    Long xxId = ...;
    
    Set<类B, Object> xxSet = new HashSet{{
    
          add(枚举C.枚举1,xxx);
    
          add(枚举C.枚举2,xxx);
    
          ...
    
    }}
    
    Map<枚举类C, Object> result = 方法名(Long xxId, Set<枚举类C> xxSet);

    看代码中并没有把XxxBolt作为参数传递,而且服务A没有依赖storm拓扑的项目,怎么日志里会打印出XxxBolt的类名呢?

    这个问题先放着,我们先回想了一下:服务A上周有过改动构建发布,storm的拓扑T的XxxBolt也有改动并发布,不过可以确定的是这段调用代码,包括请求参数,是没有改动的;

    刚才提到,服务A依赖了包B,包B也有改动;那么拓扑T是否是在服务A、包C构建之后构建发布的呢?(虽然记忆中是按的这个顺序)

    在jenkins上查看构建记录,包B是9月5号上午11点构建的,服务A是下午4点构建发布的,我们这边的拓扑T是下午5点以后构建发布的;

    在storm UI上去看拓扑的Uptime,已启动了5天多10多个小时,推算下时间,也证明拓扑T是构建后重启的;

    综上2点,说明拓扑T的依赖(A和B)都是最新的,应该不存在provider和consumer枚举C类不一致的问题。

    跟同事沟通确定这点后都有些疑惑。尝试把拓扑T构建打包后的jar下到本地,解压出来看class文件,发下XxxBolt类所在包下,不仅有XxxBolt.class,还多了一个XxxBolt$1.class;

    再回头看日志'com.xxx.XxxBolt$1' is an unknown class,这时才注意到日志里说找不到类的名称,XxxBolt后面多了$1,之前看漏了- -!

    想起java编译生成class文件,如果定义了内部类会产生xxx$xxx的class文件;

    可记得XxxBolt类里面并没有定义内部类啊,翻看一遍代码确实没有。

    用反编译工具打开XxxBolt$1.class:

    import com.xxx.枚举B;
    import java.util.HashSet;
    
    class 1 extends HashSet<枚举B>
    {
    }
    

    类名是1,这样XxxBolt$1名称解释得通,但它是哪里产生的呢? 

    刚才枚举B已确定是最新的,于是我们把目光锁定在了这个HashSet的构造上

    Set<类B, Object> xxSet = new HashSet{{
    
          add(枚举C.枚举1,xxx);
    
          add(枚举C.枚举2,xxx);
    
          ...
    
    }}

    这里使用了快捷的初始化数据语法,即在{{}}里用add的方式;
    尝试把XxxBolt代码里的某个Map xxx = new HashMap也用这种写法,重新编译发现生成了XxxBolt$2.class,反编译打开是class 2 extends HashMap<>...

    那么问题找到了,拉分支把这段代码修改下:

    Set<类B, Object> xxSet = new HashSet<类B, Object>();
    xxSet.add(枚举C.枚举1, xxx);
    xxSet.add(枚举C.枚举2, xxx);
    ...

    用普通的初始化方式,先new好,在用对象调add方法。

    重新编译就只有XxxBolt.class了。

    依次合并代码至主干后,重新构建发布并重启拓扑T,再观察服务A中已没有这个警告日志了。

    问题解决:)

    -------------------------------------------------------------------------------------------------------------------------------------------------

    总结:

    dubbo服务provider和consumer中入参要保持一致,入参vo有类型或结构变动,consumer端需要跟着provider构建,依赖最新的包;

    HashSet、HashMap用快捷初始化语法时,编译会产生内部类,以Xxx$1这种命名方式,在dubbo接口方法参数中如果用Set、Map类型,则需要注意用普通的方式初始化;

    -------------------------------------------------------------------------------------------------------------------------------------------------

    参考:

    【解决】hessian 客户端报警告:Hessian/Burlap: xxx is an unknown class in sun.misc.Launcher…… https://blog.csdn.net/fangzhangsc2006/article/details/7975978

    警告: Hessian/Burlap: 'com.github.pagehelper.Page' is an unknown class in WebappClassLoader https://blog.csdn.net/qq_38765404/article/details/78108780

  • 相关阅读:
    SCAU 9504 面试
    SCAU 9503 懒人选座位
    SCAU 8628 相亲
    SCAU 10691 ACM 光环
    SCAU 8626 原子量计数
    SCAU 10674 等差对
    HDU ACM 1048 The Hardest Problem Ever (水题)
    SCAU 9502 ARDF
    SCAU 10686 DeathGod不知道的事情
    SCAU 8629 热身游戏(高精度)
  • 原文地址:https://www.cnblogs.com/cdfive2018/p/9638327.html
Copyright © 2020-2023  润新知