做金融類網(wǎng)站西安企業(yè)seo外包服務(wù)公司
假ArrayList導(dǎo)致的線上事故…
線上事故回顧
- 晚飯時,當(dāng)我正沉迷于排骨煲肉質(zhì)鮮嫩,湯汁濃郁時,產(chǎn)研溝通群內(nèi)發(fā)出一條消息,顯示用戶存在可用劵,但進(jìn)去劵列表卻什么也沒有,并附含了一個視頻。于是我一邊吃了排骨,一邊查看消息點開了視頻,en~,視頻跟描述一樣。但沒有系統(tǒng)告警,用戶界面也沒有明顯的報錯提示,懷疑是小部分特殊情況導(dǎo)致的,查看消息后幾秒,我直接被@來處理問題,擦,只好把外賣盒重新蓋好,先去處理問題。
處理經(jīng)過
-
通過群內(nèi)產(chǎn)品發(fā)的用戶郵箱查到了用戶id,再根據(jù)接口的相關(guān)日志結(jié)合uid在日志平臺進(jìn)行關(guān)聯(lián)查詢,查到日志后,再拿到traceId進(jìn)行鏈路查詢,果不其然,發(fā)現(xiàn)了異常日志,如下部分日志所示
-
java.lang.UnsupportedOperationException: nullat java.util.AbstractList.add(AbstractList.java:148) ~[na:1.8.0_151]at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_151]
-
這
UnsupportedOperationException
是個什么玩意 -
@Slf4j @SpringBootTest public class Demo {public void test(Context context) { context.getList().add("皮皮蝦");}}@Data class Context {private List<String> list;}
-
基本操作就是拿到上下文中的List,然后再add一個元素
-
講道理,add操作是不會有問題的,有問題的還得是List,追根溯源,讓我康康這個List是怎么來的于是我一頓狂點,來到了set這個list的位置
-
@Slf4j @SpringBootTest public class Demo {public void test(Context context) {context.setList(Arrays.asList("皮皮蝦"));}}@Data class Context {private List<String> list;}
-
context.setList(Arrays.asList("Code皮皮蝦"));
這行看起來好像沒問題啊Arrays.asList(T... a)
我們平時也會用,傳入一個數(shù)組,返回出一個List
沒啥問題呀 -
那我再試試
add
方法 ,擦,問題復(fù)現(xiàn)了,還真是Arrays.asList(T... a)
生成的List
的add方法報錯,由于線上存在問題,則先修改為以下代碼上線,也就是修改為我們平時正常的寫法, 上線后,觀察了下日志,群里回復(fù)已解決問題,也讓用戶重試,發(fā)現(xiàn)沒問題,自此問題解決。
追根溯源
-
進(jìn)入
asList
方法,發(fā)現(xiàn)底層new
了一個ArrayList
,并將數(shù)組傳入作為List
的元素 -
@SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList(T... a) {return new ArrayList<>(a); }
-
emm,看起來很簡單啊,沒問題啊,咋會報錯呢?別著急,咱們在點開這個
ArrayList
瞅瞅 -
private static class ArrayList<E> extends AbstractList<E>implements RandomAccess, java.io.Serializable {private static final long serialVersionUID = -2764017481108945198L;private final E[] a;ArrayList(E[] array) {a = Objects.requireNonNull(array);}// ... 省略 }
-
擦,這
ArrayList
是Arrays
類的一個靜態(tài)內(nèi)部類,不是我們經(jīng)常用的java.util.ArrayList
繼續(xù)看,這個靜態(tài)內(nèi)部類ArrayList
繼承了AbstractList
,而且默認(rèn)是沒有實現(xiàn)add
方法的.也就是說調(diào)用add
方法會直接調(diào)用父類,也就是AbstractList
的add
方法,源碼點開一看,真相大白了.AbstractList
的add
方法直接拋出UnsupportedOperationException
異常,跟線上報錯一模一樣!!