有这样一个需求,当调用某个方法抛出异常,比如通过 HttpClient 调用远程接口时由于网络原因报 TimeOut 异常;或者所请求的接口返回类似于“处理中”这样的信息,需要重复去查结果时,我们希望当前方法能够在这种特定的情况下,重复执行,如果达到了我们的期望,则不重复执行。而且,我们希望能够控制重试次数,不希望无限期执行下去。

Java 中有各种定时任务的实现,如 Spring 的 Schedule,Quartz 等,稍微想一下,显然不符合我们的需求。递归倒是可以,但是有些问题,先看下递归的实现:

    private int retryTimes = 3;@Testpublic void upperMethod() {method("123", "456");}public void method(String param1, String param2) {System.out.println(param1 + param2);// 其他一些操作,但是没有得到预期的返回结果,或者抛出异常boolean isException = true;if(isException && retryTimes > 0){retryTimes --;method(param1, param2);}}

method 方法是需要重复执行的,重复执行 3 次,加上第一次执行,一共 4 次。如果异常了,则在 catch 里面递归调用 method。如果返回“处理中”等情况,则进行判断,是否需要递归调用。

这里的问题是定义了 retryTimes 这样一个全局变量,不优雅,如果需要重复执行的方法较多,而且重复次数不一样,则需定义多个全局变量。递归可以优化一下:

    @Testpublic void upperMethod() {method(3, "123", "456");}public void method(int retryTimes,String param1, String param2) {System.out.println(param1 + param2);// 其他一些操作,但是没有得到预期的返回结果,或者抛出异常boolean isException = true;if(isException && retryTimes > 0){method(--retryTimes, param1, param2);}}

这里去掉了全局变量,但是 method 方法多了一个和自身逻辑无关的 retryTimes 变量,还不优雅。如果参数较多,还会显得混乱。

下面做了一个还算优雅的方法:

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

增加了一个 RetryUtil 的工具类,设置重试次数,然后传入当前方法的参数,进行重复执行。这里的重点就是 RetryUtil 的实现:

public class RetryUtil {private static ThreadLocal<Integer> retryTimesInThread = new ThreadLocal<>();/*** 设置当前方法重试次数** @param retryTimes* @return*/public static RetryUtil setRetryTimes(Integer retryTimes) {if (retryTimesInThread.get() == null)retryTimesInThread.set(retryTimes);return new RetryUtil();}/*** 重试当前方法* <p>按顺序传入调用者方法的所有参数</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;}}
}

为了防止多线程情况下出现并发问题,这里定义了一个 ThreadLocal 变量来存储当前线程的重试次数。然后通过 setRetryTimes ,一个静态方法来设置这个重试次数,并返回一个 RetryUtil 对象。

调用者通过返回的 RetryUtil 对象调用 retry 方法实现重试。retry 方法接收一个可变参数,因为调用者实际的参数不确定,这里要求按顺序传入调用者方法的所有参数。

接下来判断 ThreadLocal 变量是否小于等于 0 ,如果是,则说明重复次数已达到,返回 null;如果不是,则让 ThreadLocal 变量减一。接下来:

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

来获取当前方法(retry)的上层方法名和上层类名。Thread.currentThread().getStackTrace() 得到线程的方法栈数组,数组的第二个元素 Thread.currentThread().getStackTrace() [1]  为当前方法栈,第三个元素 Thread.currentThread().getStackTrace() [2] 为上层方法栈,通过上层方法的栈帧得到上层方法的方法名和类名。

下面就是通过反射获取该类的所有方法,循环判断方法名是否等于所要重复执行的方法,如果是的话,执行该方法,参数就是传入可变参数。

可能大家会说反射会耗时,但我认为对于上述这种需求的情况,重试次数也不会太多,因此性能可以接受。

转载于:https://www.cnblogs.com/itplay/p/10771861.html

java-retry实现相关推荐

  1. java retry(重试) spring retry, guava retrying 详解

    转载 自 http://blog.51cto.com/9250070/2156431 系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理 ...

  2. java retry: 详解

    java retry: 详解 发现 验证 结论 反编译验证结论 启发 扩展 发现 今天在探索线程池实现原理的时候,遇到一个重来没有见过的语法,通过网上查阅资料,自己也做了验证 验证 通过查阅资料,re ...

  3. java retry 设置上限_java-如何设置Spring Retry模板重试最大尝试次数:无限

    我想用Spring Retry修改数据库连接的创建,以便在应用程序启动时数据库关闭时再试一次.我不想限制重试次数.我应该如何配置策略来做到这一点. 我当前的代码(我知道在这种状态下它限制为100): ...

  4. java retry 实现,java-retry实现

    有这样一个需求,当调用某个方法抛出异常,比如通过 HttpClient 调用远程接口时由于网络原因报 TimeOut 异常:或者所请求的接口返回类似于"处理中"这样的信息,需要重复 ...

  5. java retry怎么用_java retry使用详解

    在说明前先来看一点代码: public void testRequest() { // retry:// 1(行2) for (int i = 0; i < 10; i++) { retry:/ ...

  6. foxmail邮件加载失败重试_java retry(重试) spring retry, guava retrying 详解

    系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理:实现一个按条件,查询用户信息的服务. 小明:好的.没问题. 代码 UserServi ...

  7. 重试机制 Retry

    文章目录 1.重试 1.1 重试作用 2.重试的三种方法 2.1 java retry 2.2 spring retry 2.3 guava-retrying 2.3.1 重试源 2.3.2 自定义重 ...

  8. java的不足_java的优势和不足

    自我评价优缺点的 1.忠实诚信,讲原则,说到做到,决不推卸责任;有自制力, 做事... SQL Server的优点和缺点_计算机软件及应用_IT/计算机_专业资料.SQ... 彩尊 彩尊注册 SQL ...

  9. 高级JAVA - 手写简单的重试组件学习Spring Retry

    目录 一 . 定义注解 二 . 利用cglib代理扩展重试业务 三 . 编写代理类 , 使用自定义的XRetryInterceptor作为拦截器 四 . 编写相关业务方法 , 测试代码 五 . 测试结 ...

  10. java中的字符retry: 是什么?

    在看源码时,出现了retry: ,这个是什么意思?之前没有接触过,那先来一个简单的例子. public void testRetry() {int i = 0;retry: //① while (tr ...

最新文章

  1. 优秀!这位70后硕士,入围中国工程院院士候选人!
  2. [Android] Gradle 安装
  3. LAMP架构之编译安装httpd+(php-fpm)+mariadb
  4. 垂直居中 absolute 和 flex 方法
  5. 轻松查看Internet Explorer缓存文件
  6. 面试了一个2年程序员,竟然只会curd,网友神回复!
  7. VB讲课笔记08:数组
  8. 【英语学习】【English L06】U06 Banking L4 I'd like to transfer some money
  9. Spring ROO初体验
  10. 掘金后端 mysql优化_vue服务端渲染项目(ssr)仿掘金、后台页面是react spa、服务层nodejs、koa、mysql编写的一套多权限内容管理系统...
  11. Oracle软件安装及手工建库
  12. (转) QImage总结
  13. 律师视角下网络爬虫技术的罪与罚
  14. 抖音极速版/快手极速版自动浏览
  15. MySQL基本操作四:数据的查询
  16. PayPal集成标准版案例(asp.net)关键源码
  17. nrf52在未配对的情况下使用白名单广播,指定安卓手机允许连接
  18. ubuntu 文件管理器推荐
  19. win10修改docker镜像的存储位置
  20. 迪赛推出国家公立医院绩效考核服务系统,融合迪赛智慧数加持赋能,让二三级医院用户领跑“国考”!

热门文章

  1. inet_ntop函数和inet_pton函数
  2. 在PC机上熟悉常用网络命令
  3. ATT汇编leave指令
  4. mac os 和 ubuntu 上测试工具check-0.9.10的安装
  5. 操作系统(十一)线程的概念和特点
  6. zcmu-1931(dfs方格切割)
  7. [Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?
  8. Android 反射、代理调用系统隐藏API方法与接口类连接Wi-Fi
  9. android标题栏添加按钮_[办公小技巧]Excel 添加页码,自定义和指定单元格页码添加...
  10. 属性与意图识别_解密宝能汽车智能驾舱的“未来属性”