日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java-retry实现

發(fā)布時(shí)間:2025/3/15 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java-retry实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

有這樣一個(gè)需求,當(dāng)調(diào)用某個(gè)方法拋出異常,比如通過(guò) HttpClient 調(diào)用遠(yuǎn)程接口時(shí)由于網(wǎng)絡(luò)原因報(bào) TimeOut 異常;或者所請(qǐng)求的接口返回類似于“處理中”這樣的信息,需要重復(fù)去查結(jié)果時(shí),我們希望當(dāng)前方法能夠在這種特定的情況下,重復(fù)執(zhí)行,如果達(dá)到了我們的期望,則不重復(fù)執(zhí)行。而且,我們希望能夠控制重試次數(shù),不希望無(wú)限期執(zhí)行下去。

Java 中有各種定時(shí)任務(wù)的實(shí)現(xiàn),如 Spring 的 Schedule,Quartz 等,稍微想一下,顯然不符合我們的需求。遞歸倒是可以,但是有些問(wèn)題,先看下遞歸的實(shí)現(xiàn):

private int retryTimes = 3;@Testpublic void upperMethod() {method("123", "456");}public void method(String param1, String param2) {System.out.println(param1 + param2);// 其他一些操作,但是沒(méi)有得到預(yù)期的返回結(jié)果,或者拋出異常boolean isException = true;if(isException && retryTimes > 0){retryTimes --;method(param1, param2);}}

method 方法是需要重復(fù)執(zhí)行的,重復(fù)執(zhí)行 3 次,加上第一次執(zhí)行,一共 4 次。如果異常了,則在 catch 里面遞歸調(diào)用 method。如果返回“處理中”等情況,則進(jìn)行判斷,是否需要遞歸調(diào)用。

這里的問(wèn)題是定義了 retryTimes 這樣一個(gè)全局變量,不優(yōu)雅,如果需要重復(fù)執(zhí)行的方法較多,而且重復(fù)次數(shù)不一樣,則需定義多個(gè)全局變量。遞歸可以優(yōu)化一下:

@Testpublic void upperMethod() {method(3, "123", "456");}public void method(int retryTimes,String param1, String param2) {System.out.println(param1 + param2);// 其他一些操作,但是沒(méi)有得到預(yù)期的返回結(jié)果,或者拋出異常boolean isException = true;if(isException && retryTimes > 0){method(--retryTimes, param1, param2);}}

這里去掉了全局變量,但是 method 方法多了一個(gè)和自身邏輯無(wú)關(guān)的 retryTimes 變量,還不優(yōu)雅。如果參數(shù)較多,還會(huì)顯得混亂。

下面做了一個(gè)還算優(yōu)雅的方法:

@Testpublic void mainMethod() {subMethod("123", "456");}public void subMethod(String param1, String param2) {System.out.println(param1 + param2);RetryUtil.setRetryTimes(3).retry(param1, param2);}

增加了一個(gè) RetryUtil 的工具類,設(shè)置重試次數(shù),然后傳入當(dāng)前方法的參數(shù),進(jìn)行重復(fù)執(zhí)行。這里的重點(diǎn)就是 RetryUtil 的實(shí)現(xiàn):

public class RetryUtil {private static ThreadLocal<Integer> retryTimesInThread = new ThreadLocal<>();/*** 設(shè)置當(dāng)前方法重試次數(shù)** @param retryTimes* @return*/public static RetryUtil setRetryTimes(Integer retryTimes) {if (retryTimesInThread.get() == null)retryTimesInThread.set(retryTimes);return new RetryUtil();}/*** 重試當(dāng)前方法* <p>按順序傳入調(diào)用者方法的所有參數(shù)</p>** @param args* @return*/public Object retry(Object... args) {try {Integer retryTimes = retryTimesInThread.get();if (retryTimes <= 0) {retryTimesInThread.remove();return null;}retryTimesInThread.set(--retryTimes);String upperClassName = Thread.currentThread().getStackTrace()[2].getClassName();String upperMethodName = Thread.currentThread().getStackTrace()[2].getMethodName();Class clazz = Class.forName(upperClassName);Object targetObject = clazz.newInstance();Method targetMethod = null;for (Method method : clazz.getDeclaredMethods()) {if (method.getName().equals(upperMethodName)) {targetMethod = method;break;}}if (targetMethod == null)return null;targetMethod.setAccessible(true);return targetMethod.invoke(targetObject, args);} catch (Exception e) {e.printStackTrace();return null;}} }

為了防止多線程情況下出現(xiàn)并發(fā)問(wèn)題,這里定義了一個(gè) ThreadLocal 變量來(lái)存儲(chǔ)當(dāng)前線程的重試次數(shù)。然后通過(guò) setRetryTimes ,一個(gè)靜態(tài)方法來(lái)設(shè)置這個(gè)重試次數(shù),并返回一個(gè) RetryUtil 對(duì)象。

調(diào)用者通過(guò)返回的 RetryUtil 對(duì)象調(diào)用 retry 方法實(shí)現(xiàn)重試。retry 方法接收一個(gè)可變參數(shù),因?yàn)檎{(diào)用者實(shí)際的參數(shù)不確定,這里要求按順序傳入調(diào)用者方法的所有參數(shù)。

接下來(lái)判斷 ThreadLocal 變量是否小于等于 0 ,如果是,則說(shuō)明重復(fù)次數(shù)已達(dá)到,返回 null;如果不是,則讓 ThreadLocal 變量減一。接下來(lái):

String upperClassName = Thread.currentThread().getStackTrace()[2].getClassName(); String upperMethodName = Thread.currentThread().getStackTrace()[2].getMethodName();

來(lái)獲取當(dāng)前方法(retry)的上層方法名和上層類名。Thread.currentThread().getStackTrace() 得到線程的方法棧數(shù)組,數(shù)組的第二個(gè)元素 Thread.currentThread().getStackTrace()?[1]? 為當(dāng)前方法棧,第三個(gè)元素?Thread.currentThread().getStackTrace() [2] 為上層方法棧,通過(guò)上層方法的棧幀得到上層方法的方法名和類名。

下面就是通過(guò)反射獲取該類的所有方法,循環(huán)判斷方法名是否等于所要重復(fù)執(zhí)行的方法,如果是的話,執(zhí)行該方法,參數(shù)就是傳入可變參數(shù)。

可能大家會(huì)說(shuō)反射會(huì)耗時(shí),但我認(rèn)為對(duì)于上述這種需求的情況,重試次數(shù)也不會(huì)太多,因此性能可以接受。

轉(zhuǎn)載于:https://www.cnblogs.com/itplay/p/10771861.html

與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的java-retry实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。