dubbo服務provider方打印警告日志,getDeserializer - Hessian/Burla 'xxx' is an unknown class


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM