一個由於侵入框架引起的故障

  • 2021 年 8 月 17 日
  • 筆記

背景

其實最近一直想寫些幫助大家提高架構底蘊的東西。無奈最近當家的身體抱恙,我白天上班,晚上照顧病人,沒有多餘的精力 點、線、面的橫向思考技術的問題。倒是「無為空自老,含嘆負平生」的人生感慨多一些。今天還是談談點上的東西。
記得早些時候,被別人要求寫演算法程式碼沒寫出來,後來我刷了百道leetcode。演算法題再也沒難住我了。但是想來,平時工作中是還是真的少些這些底層程式碼為妙,業務程式碼有業務程式碼的寫法。寫業務程式碼最忌諱:「炫技」。和做人一樣,講究「技高不炫技」。下面來介紹一個由於侵入了框架內部引起的故障。

 

使用Java反射引起的報錯

我們平時用Spring框架寫Controller進行http請求處理時,框架幫我們做了JavaBean到傳輸數據的轉換。在內部,實際上數據會先轉成map再轉成我們要處理的JavaBean。這次,在一個RPC泛化調用的場景(泛化調用主要用於沒有介面API的情況下。不需要引入介面 jar 包,而是直接通過 通用介面來發起服務調用,參數及返回值中的所有 pojo均用 map 表示)。有個同學客戶端處理時,自己寫了一個JavaBean轉成Map的方式,他是這麼寫的:

public static Map<String,Object> objectTpMap(Object obj) {

     Map<String,Object> map = new HashMap();

     Class objectClass = obj.getClass();

     while(objectClass != null) {

          Field[] declaredFields = objectClass.getDeclaredFields();

          for(Field field : declaredFields) {

               field.setAccessible(true);

               resultMap.put(field.getName(), field.get(object));

          }

     }

     return resultMap;

}

這裡,在做JavaBean到Map轉化時,用了反射的方法,將對象的所有屬性(包含private final類型)都提取出來,傳給服務端。服務端組件內部,開始時反序列化時,使用的是getField方法查找這個map中的每一個key。如果對象是private final類型是獲取不到的,所以沒有影響。後來組件升級,反序列化時,並沒有使用getField方法,而是使用了getDeclaredField方法,就可以獲取到private final類型的屬性,進行賦值操作的時候就產生了問題。
這個bug經過了一兩年時間才引起了事故。讓人意想不到,恢復和排查的響應時間都會收到影響。

 

後記

能寫出這樣的程式碼,究其原因,大致有兩種:一種遇到這個問題,經過搜索資料和思考,覺得這樣可以實現,就沒有做更多的思考;另一種是抱著學習的態度,想用一些之前不常用的技術解決問題。這兩種原因寫出的程式碼都是建立在對原理了解不透徹的基礎上,相當危險。
最近在看《山河令》,裡面有個詩詞底蘊極高的溫客行。說話時引經據典,天花亂墜。見到周子舒渡船,溫客行說:「但度無所苦,我自迎接汝」。這本是大文豪王獻之寫給他的愛妾桃葉的詩。因為桃葉怕坐船,王獻之就說了:「你只管渡江就好,不用想太多,我自然會在江邊迎接你。」這裡溫客行用的隱隱表露出自己的小心思,倒也用的妙。
為了和溫客行做對比,裡面還出現了個愛附庸風雅的大白兔:曹蔚寧。小曹喜歡阿湘。於是跟阿湘誇她名字好:「九嶷繽兮並迎,靈之來兮如雲。」句子里沒有出現一個「湘」字。和湘沾邊的是前半句「九嶷繽兮並迎「出自屈原的《九歌.湘夫人》。而後半句是曹植的《洛神賦》。洛神叫甄宓啊,和湘字沒有半毛錢關係,純粹是背詩背串了。所以溫客行說聽小曹背詩,屈原都能被氣活過來。這境界反差出來了吧。
但是強如溫客行,人家在河邊喝水,他本是想打招呼示好的話。他來了一首:「滄浪之水清兮,可以濯我纓;滄浪之水濁兮,可以濯我足。」我只是覺得人家在喝水,你又是洗衣服又是洗腳的,這水喝著真倒胃口。你倒是來一首:「問渠那得清如許?為有源頭活水來。」 也能讓人覺得水的甘甜。或者來首:「秋水清無底,蕭然靜客心。」 也可在這炎炎夏日送上一抹涼意。也難怪周子舒不理他。
溫客行的漏洞可不止這一處,溫客行造了30個假的琉璃甲,帶著周子舒去看狗咬狗。他在屋頂上說的是:「衝天香陣透岳陽,滿城儘是琉璃甲」。這本是黃巢寫菊花的詩:「衝天香陣透長安,滿城盡帶黃金甲。」 你要是改,也要改的徹底一點,人家菊花是香的,香陣一詞用的妙,琉璃甲和香有什麼關係嗎?衝天香陣肯定是沒有,衝天的殺氣卻是名副其實。說這麼多,無非是想說明,還是要敬畏生產。不了解原理還是不要直接在要上生產的程式碼里嘗試。侵入框架底層的程式碼最好不要寫,盡量看看能否用寫業務程式碼的方式來解決。連溫客行身上都能找到這麼多詩詞的錯處,平時咱們寫的業務程式碼還怕找不出來Bug?一旦出現生產事故,豈不是丟了排面?

 

推薦閱讀

程式碼榮辱觀-以運用風格為榮,以隨意編碼為恥

工作中溝通的4點感悟

知名互聯網公司需要什麼樣的人才

《兩地書》–K8s基礎知識