java-retry实现
有这样一个需求,当调用某个方法抛出异常,比如通过 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实现相关推荐
- java retry(重试) spring retry, guava retrying 详解
转载 自 http://blog.51cto.com/9250070/2156431 系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理 ...
- java retry: 详解
java retry: 详解 发现 验证 结论 反编译验证结论 启发 扩展 发现 今天在探索线程池实现原理的时候,遇到一个重来没有见过的语法,通过网上查阅资料,自己也做了验证 验证 通过查阅资料,re ...
- java retry 设置上限_java-如何设置Spring Retry模板重试最大尝试次数:无限
我想用Spring Retry修改数据库连接的创建,以便在应用程序启动时数据库关闭时再试一次.我不想限制重试次数.我应该如何配置策略来做到这一点. 我当前的代码(我知道在这种状态下它限制为100): ...
- java retry 实现,java-retry实现
有这样一个需求,当调用某个方法抛出异常,比如通过 HttpClient 调用远程接口时由于网络原因报 TimeOut 异常:或者所请求的接口返回类似于"处理中"这样的信息,需要重复 ...
- java retry怎么用_java retry使用详解
在说明前先来看一点代码: public void testRequest() { // retry:// 1(行2) for (int i = 0; i < 10; i++) { retry:/ ...
- foxmail邮件加载失败重试_java retry(重试) spring retry, guava retrying 详解
系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理:实现一个按条件,查询用户信息的服务. 小明:好的.没问题. 代码 UserServi ...
- 重试机制 Retry
文章目录 1.重试 1.1 重试作用 2.重试的三种方法 2.1 java retry 2.2 spring retry 2.3 guava-retrying 2.3.1 重试源 2.3.2 自定义重 ...
- java的不足_java的优势和不足
自我评价优缺点的 1.忠实诚信,讲原则,说到做到,决不推卸责任;有自制力, 做事... SQL Server的优点和缺点_计算机软件及应用_IT/计算机_专业资料.SQ... 彩尊 彩尊注册 SQL ...
- 高级JAVA - 手写简单的重试组件学习Spring Retry
目录 一 . 定义注解 二 . 利用cglib代理扩展重试业务 三 . 编写代理类 , 使用自定义的XRetryInterceptor作为拦截器 四 . 编写相关业务方法 , 测试代码 五 . 测试结 ...
- java中的字符retry: 是什么?
在看源码时,出现了retry: ,这个是什么意思?之前没有接触过,那先来一个简单的例子. public void testRetry() {int i = 0;retry: //① while (tr ...
最新文章
- 优秀!这位70后硕士,入围中国工程院院士候选人!
- [Android] Gradle 安装
- LAMP架构之编译安装httpd+(php-fpm)+mariadb
- 垂直居中 absolute 和 flex 方法
- 轻松查看Internet Explorer缓存文件
- 面试了一个2年程序员,竟然只会curd,网友神回复!
- VB讲课笔记08:数组
- 【英语学习】【English L06】U06 Banking L4 I'd like to transfer some money
- Spring ROO初体验
- 掘金后端 mysql优化_vue服务端渲染项目(ssr)仿掘金、后台页面是react spa、服务层nodejs、koa、mysql编写的一套多权限内容管理系统...
- Oracle软件安装及手工建库
- (转) QImage总结
- 律师视角下网络爬虫技术的罪与罚
- 抖音极速版/快手极速版自动浏览
- MySQL基本操作四:数据的查询
- PayPal集成标准版案例(asp.net)关键源码
- nrf52在未配对的情况下使用白名单广播,指定安卓手机允许连接
- ubuntu 文件管理器推荐
- win10修改docker镜像的存储位置
- 迪赛推出国家公立医院绩效考核服务系统,融合迪赛智慧数加持赋能,让二三级医院用户领跑“国考”!
热门文章
- inet_ntop函数和inet_pton函数
- 在PC机上熟悉常用网络命令
- ATT汇编leave指令
- mac os 和 ubuntu 上测试工具check-0.9.10的安装
- 操作系统(十一)线程的概念和特点
- zcmu-1931(dfs方格切割)
- [Android]用架构师角度看插件化(3)-Replugin 需要占坑跳转?
- Android 反射、代理调用系统隐藏API方法与接口类连接Wi-Fi
- android标题栏添加按钮_[办公小技巧]Excel 添加页码,自定义和指定单元格页码添加...
- 属性与意图识别_解密宝能汽车智能驾舱的“未来属性”