Java中的重試機制,還有誰不會!
時間:2023-10-20 來源:華清遠見
隨著互聯網的發展項目中的業務功能越來越復雜,有一些基礎服務我們不可避免的會去調用一些第三方的接口或者公司內其他項目中提供的服務,但是遠程服務的健壯性和網絡穩定性都是不可控因素。在測試階段可能沒有什么異常情況,但上線后可能會出現調用的接口因為內部錯誤或者網絡波動而出錯或返回系統異常,因此我們必須考慮加上重試機制。
重試機制:可以提高系統的健壯性,并且減少因網絡波動依賴服務臨時不可用帶來的影響,讓系統能更穩定的運行。
1、手動重試
手動重試:使用 while 語句進行重試:


上述代碼看上去可以解決重試問題,但實際上存在一些弊端:
1、由于沒有重試間隔,很可能遠程調用的服務還沒有從網絡異常中恢復,所以有可能接下來的幾次調用都會失敗
2、代碼侵入式太高,調用方代碼不夠優雅
3、項目中遠程調用的服務可能有很多,每個都去添加重試會出現大量的重復代碼
2、靜態代理
上面的處理方式由于需要對業務代碼進行大量修改,雖然實現了功能,但是對原有代碼的侵入性太強,可維護性差。所以需要使用一種更優雅一點的方式,不直接修改業務代碼,那要怎么做呢?
其實很簡單,直接在業務代碼的外面再包一層就行了,代理模式在這里就有用武之地了。

這樣,重試邏輯就都由代理類來完成,原業務類的邏輯就不需要修改了,以后想修改重試邏輯也只需要修改這個類就行了。
代理模式雖然要更加優雅,但是如果依賴的服務很多的時候,要為每個服務都創建一個代理類,顯然過于麻煩,而且其實重試的邏輯都大同小異,無非就是重試的次數和延時不一樣而已。如果每個類都寫這么一長串類似的代碼,顯然,不優雅!
3、JDK動態代理
這時候,動態代理就閃亮登場了。只需要寫一個代理處理類就 ok 了


動態代理可以將重試邏輯都放到一塊,顯然比直接使用代理類要方便很多,也更加優雅。
這里使用的是JDK動態代理,因此就存在一個天然的缺陷,如果想要被代理的類,沒有實現任何接口,那么就無法為其創建代理對象,這種方式就行不通了
4、CGLib 動態代理
既然已經說到了 JDK 動態代理,那就不得不提 CGLib 動態代理了。使用 JDK 動態代理對被代理的類有要求,不是所有的類都能被代理,而 CGLib 動態代理則剛好解決了這個問題。



這樣就很棒了,完美的解決了JDK動態代理帶來的缺陷。優雅指數上漲了不少。
但這個方案仍舊存在一個問題,那就是需要對原來的邏輯進行侵入式修改,在每個被代理實例被調用的地方都需要進行調整,這樣仍然會對原有代碼帶來較多修改。
5、手動AOP
考慮到以后可能會有很多的方法也需要重試功能,咱們可以將重試這個共性功能通過 AOP 來實現:使用 AOP 來為目標調用設置切面,即可在目標方法調用前后添加一些重試的邏輯。



這樣即不用編寫重復代碼,實現上也比較優雅了:一個注解就實現重試。

