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

程式設計一生發表於2021-08-16

背景

其實最近一直想寫些幫助大家提高架構底蘊的東西。無奈最近當家的身體抱恙,我白天上班,晚上照顧病人,沒有多餘的精力 點、線、面的橫向思考技術的問題。倒是“無為空自老,含嘆負平生”的人生感慨多一些。今天還是談談點上的東西。
記得早些時候,被別人要求寫演算法程式碼沒寫出來,後來我刷了百道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基礎知識

相關文章