本篇文章给大家分享的是有关如何用Guava Retrying,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。重试的使用场景 在很多业务场景中,为了排除系统中的各种不稳定因素,以及逻辑上的错误,并最大概率保证获得预期的结果,重试机制都是必不可少的。 尤其是调用远程服务,在高并发场景下,很可能因为服务器响应延迟或者网络原因,造成我们得不到想要的结果,或者根本得不到响应。这个时候,一个优雅的重试调用机制,可以让我们更大概率保证得到预期的响应。 sequenceDiagram Client->>Server:{“msg”:”hello,server”} Note right of Server: busying …… Client->>Server:{“msg”:”hello,server”}通常情况下,我们会通过定时任务进行重试。例如某次操作失败,则记录下来,当定时任务再次启动,则将数据放到定时任务的方法中,重新跑一遍。最终直至得到想要的结果为止。 无论是基于定时任务的重试机制,还是我们自己写的简单的重试器,缺点都是重试的机制太单一,而且实现起来不优雅。 如何优雅地设计重试实现 一个完备的重试实现,要很好地解决如下问题:什么条件下重试 什么条件下停止 如何停止重试 停止重试等待多久 如何等待 请求时间限制 如何结束 如何监听整个重试过程并且,为了更好地封装性,重试的实现一般分为两步:使用工厂模式构造重试器 执行重试方法并得到结果一个完整的重试流程可以简单示意为: graph LR A((Start)) –>|build| B(Retryer) B –> C{need call?} C –>|continue| D[call] D –> Z[call count++] Z –> C C –>|finished| E[result] E –> F((success)) E –> G((failed ))guava-retrying基础用法 guava-retrying是基于谷歌的核心类库guava的重试机制实现,可以说是一个重试利器。 下面就快速看一下它的用法。 1.Maven配置
} }自定义重试监听器RetryListener可以监控多次重试过程,并可以使用attempt做一些额外的事情。 package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.listener;import com.github.rholder.retry.Attempt; import com.github.rholder.retry.RetryListener; import lombok.extern.slf4j.Slf4j;@Slf4j public class RetryLogListener implements RetryListener {}自定义Exception有些异常需要重试,有些不需要。 package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.exception;/**当抛出这个异常的时候,表示需要重试 */ public class NeedRetryException extends Exception {public NeedRetryException(String message) { super(“NeedRetryException can retry.”+message); }}实现具体重试业务与Callable接口使用call方法调用自己的业务。 package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.model;import lombok.AllArgsConstructor; import lombok.Data;import java.math.BigDecimal;/**商品model */ @Data @AllArgsConstructor public class Product {private Long id;private String name;private Integer count;private BigDecimal price;}package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.repository;import net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.model.Product; import org.springframework.stereotype.Repository;import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong;/**商品DAO */ @Repository public class ProductRepository {private static ConcurrentHashMap
}}构造重试器Retryer将上面的实现作为参数,构造Retryer。 package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.service;import com.github.rholder.retry.*; import net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.exception.NeedRetryException; import net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.listener.RetryLogListener; import net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.strategy.SpinBlockStrategy; import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/**构造重试器 */ @Component public class ProductRetryerBuilder {public Retryer build() { //定义重试机制 Retryer
} }与定时任务结合执行Retryer定时任务只需要跑一次,但是实际上实现了所有的重试策略。这样大大简化了定时器的设计。 首先使用@EnableScheduling声明项目支持定时器注解。 @SpringBootApplication @EnableScheduling public class DemoRetryerApplication { public static void main(String[] args) { SpringApplication.run(DemoRetryerApplication.class, args); } }package net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.task;import com.github.rholder.retry.Retryer; import net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.service.ProductInformationHander; import net.ijiangtao.tech.framework.spring.ispringboot.demo.retryer.guava.service.ProductRetryerBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;/**商品信息定时器 */ @Component public class ProductScheduledTasks {@Autowired private ProductRetryerBuilder builder;@Autowired private ProductInformationHander hander;/**同步商品价格定时任务@Scheduled(fixedDelay = 30000) :上一次执行完毕时间点之后30秒再执行 _/ @Scheduled(fixedDelay = 30_1000) public void syncPrice() throws Exception{ Retryer retryer=builder.build(); retryer.call(hander); }}执行结果:由于并没有商品,因此重试以后,抛出异常。 2019-二月-28 14:37:52.667 INFO [scheduling-1] n.i.t.f.s.i.d.r.g.l.RetryLogListener – log listen over. 2019-二月-28 14:37:52.672 ERROR [scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler – Unexpected error occurred in scheduled task. com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts. at com.github.rholder.retry.Retryer.call(Retryer.java:174)你也可以增加一些商品数据,看一下重试成功的效果。 完整示例代码在这里。 使用中遇到的问题 Guava版本冲突 由于项目中依赖的guava版本过低,启动项目时出现了如下异常。 java.lang.NoSuchMethodError: com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor()Lcom/google/common/util/concurrent/ListeningExecutorService; at org.apache.curator.framework.listen.ListenerContainer.addListener(ListenerContainer.java:41) at com.bzn.curator.ZkOperator.getZkClient(ZkOperator.java:207) at com.bzn.curator.ZkOperator.checkExists(ZkOperator.java:346) at com.bzn.curator.watcher.AbstractWatcher.initListen(AbstractWatcher.java:87) at com.bzn.web.listener.NebulaSystemInitListener.initZkWatcher(NebulaSystemInitListener.java:84) at com.bzn.web.listener.NebulaSystemInitListener.contextInitialized(NebulaSystemInitListener.java:33) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)因此,要排除项目中低版本的guava依赖。
类似的效果也可以通过自定义 BlockStrategy 来实现,你可以写一下试试。*/ public class AlipayWaitStrategy implements WaitStrategy {}以上就是如何用Guava Retrying,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注开发云行业资讯频道。
本篇内容介绍了“Java虚拟机是怎么加载Java类的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java 虚拟机中的类加载即从 class 文件到内存中的类,…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。