一、前言
今天在增加完新功能後, 部署的時候,突然就遇到了java.io.InvalidClassException的問題,這些都是我們平常不注意細節造成的後果。
具體異常如下
分析異常:Caused by:java. io. InvalidClassException: com. eastcom xxx.xxxxxx. bean. AlarmReq; local class incompatible: stream classdesc serialversionUID =1631280650588763177, local class seriaiversionuId = 6638111461888145730
二、分析原因
首先我們的系統架構,是因爲要將對象通過
AlarmReq alarmReq= JSONObject.toJavaObject(json,AlarmReq.class);
redisQueue = redisTaskContainer.getRedisQueue();
redisQueue.pushFromHead(alarmReq);
上述方法會將對象序列化到redis內存中,然後又再通過 redisTemplate.getValueSerializer().deserialize() 方法將數據反序列化到bean對象,這樣的話,如果改動了這個bean對象的話,即加了屬性的話,就會導致serialVersionUID會變,而且當時我們的bean對象即上述的AlarmReq對象,當時是沒有加serialVersionUID的。
由於序列化時該類的serialVersionUID是JVM根據類名及其屬性的哈希值生成的。當類的屬性有變動時,serialVersionUID也會相應變動,從而導致redis中的老數據反序列化爲AlarmReq bean對象時,serialVersionUID匹配不上而失敗,會報出java. io. InvalidClassException。
三、解決問題
知道原因了,我們就可以解決問題了
方法1:不考慮和老數據兼容的話,直接在你實現了Serializable的這個對象加一段serialVersionUID代碼,如果還報InvalidClassException,將redis上的老數據清除
private static final long serialVersionUID = 1L;
方法2:兼容老數據,找到老數據的serialVersionUID,就是上述報錯的地方,會將老數據的serialVersionUID報出來,比如我這裏的老數據的就是1631280650588763177 這一串,你只要加 UID=1631280650588763177 這個就可以了。
private static final long serialVersionUID = 1631280650588763177L;
四、總結
可能好多人在寫對象以及序列化對象的時候,是沒有加private static final long serialVersionUID的,但是也沒有見到有報InvalidClassException異常的,那是因爲你部署的單體系統架構,實時序列化和反序列化的,每次系統重啓就又重新實例對象,所以即使改變了對象增加屬性,也不會出現老對象和新對象serialVersionUID 不一致的情況,所以也就不會出現java. io. InvalidClassException。
所以以後你們寫對象並且要序列化的話,一定要隨手加上serialVersionUID這段代碼。
如果你們去看源碼,HashMap、ArrayList 等這些神級代碼的時候,你們可以看到,他們都是加了 serialVersionUID 代碼的
五、使用idea工具自動生成
1、按照下圖所示,設置好後,不要忘記點擊【Apply】應用一下
2、在實現了 Serializable的bean類下, 鼠標移到bean類名處,按住 alt+enter,就會自動彈出【Add serialVersionUID field】
選中即可自動生成啦,
參考文章:
https://blog.csdn.net/z3278221/article/details/90298812
感謝原作者的分享,讓技術人能夠更快的解決問題