当前位置: 首页 > news >正文

网站开发的缺点武汉网络推广有限公司

网站开发的缺点,武汉网络推广有限公司,杭州品牌策划,网站用户注册怎么建目录 1、前言 2、实现方式 2.1、循环重试 2.2、递归重试 2.3、Spring Retry 2.4、Resilience4j 2.5、http请求网络工具内置重试方式 2.6、自定义重试工具 2.7、并发框架异步重试 2.8、消息队列 3、小结 1、前言 HTTP接口请求重试是指在请求失败时,再次发…

 目录

1、前言

2、实现方式

2.1、循环重试

2.2、递归重试

2.3、Spring Retry

2.4、Resilience4j

2.5、http请求网络工具内置重试方式

2.6、自定义重试工具

2.7、并发框架异步重试

2.8、消息队列

3、小结


1、前言

HTTP接口请求重试是指在请求失败时,再次发起请求的机制。在实际应用中,由于网络波动、服务器故障等原因,HTTP接口请求可能会失败。为了保证系统的可用性和稳定性,需要对HTTP接口请求进行重试。

2、实现方式

今天给大家分享一些常见的接口请求重试的方式。本地模拟了一个请求接口,后面的代码示例均模拟请求该接口:

@GetMapping("http_test")
public String getHttpTest(){return "接口请求成功,返回:OK";
}

2.1、循环重试

循环重试是最简单最粗暴的方式,就是在请求接口代码中加入循环机制,如果接口请求失败,则循环继续发起接口请求,直到请求成功或接口重试次数达到上限。如果请求成功,则不进行重试。

简单代码示例如下:

@GetMapping("retry_demo_loop")
public String retry_demo_loop(){// 重试上限次数为3次int maxRetryTime = 3;String result = null;// 接口循环请求for (int i = 1; i <= maxRetryTime; i++) {try {// 模拟请求接口result = HttpUtil.get("http://localhost:8080/http_test");// 模拟一次请求失败if(i == 1){int co = i / 0;}// 请求成功,跳出循环break;} catch (Exception e) {log.error("接口请求异常,进行第{}次重试", i);result = "接口请求失败,请联系管理员";}}return result;
}

请求结果:

重试日志打印:

2.2、递归重试

除了循环,还可以使用递归来实现接口的请求重试。递归是我们都比较熟悉的编程技巧,在请求接口的方法中调用自身,如果请求失败则继续调用,直到请求成功或达到最大重试次数。

@GetMapping("retry_demo_rec")
public String retry_demo_rec(){// 重试上限次数为3次int maxRetryTime = 3;return retryRequest(maxRetryTime);
}/*** 递归方法* @param maxRetryTime* @return*/
private String retryRequest(int maxRetryTime){if (maxRetryTime <= 0) {return "接口请求失败,请联系管理员";}int retryTime = 0;try {// 模拟请求接口String result = HttpUtil.get("http://localhost:8080/http_test");// 模拟一次请求失败if(maxRetryTime == 3){int co = 1 / 0;}return result;} catch (Exception e) {// 处理异常log.error("接口请求异常,进行第{}次重试", ++retryTime);return retryRequest(maxRetryTime - 1);}
}

请求结果:

重试日志打印:

2.3、Spring Retry

第三种便是使用Spring Retry依赖实现。首先我们需要集成相关依赖:

<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId>
</dependency>
<!-- 由于retry使用到了aop,所以还需要加入aop依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

加入@EnableRetry启动:

@EnableRetry
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

添加retry方法注解:

public interface MyRetryService {/*** retryable注解表示该方法需要重试* value:出现该指定异常后,进行重试* maxAttempts:重试次数上限,这里指定为3次* backoff:重试策略,这里指定200ms间隔一次* @param code* @return* @throws Exception*/@Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(200))String retry(int code) throws Exception;/*** 当重试达到上限后还是失败,则作为异常回调方法* @param th* @param code* @return*/@RecoverString recover(Throwable th, int code);}

MyReretService实现类:

@Slf4j
@Service
public class MyRetryServiceImpl implements MyRetryService {@Overridepublic String retry(int code) throws Exception {log.info("请求retry接口");String result = HttpUtil.get("http://localhost:8080/http_test");if(code != 200){throw new Exception("接口请求异常");}return result;}@Overridepublic String recover(Throwable th, int code) {log.error("回调方法执行!!!!");return "异常码为:" + code + ",异常信息:" + th.getMessage();}
}

Controller:

@Autowired
private MyRetryService myRetryService;/*** 当请求code参数为200时,直接成功* 当code参数!=200时,会出发重试* @param code* @return* @throws Exception*/
@GetMapping("retry_demo_spring_retry")
public String retry_demo_spring_retry(Integer code) throws Exception {return myRetryService.retry(code);
}

访问地址:http://localhost:8080/retry_demo_spring_retry?code=123

查看结果:可以看到接口重试了3次,最后执行了@Recover方法最后的回调。

2.4、Resilience4j

Resilience4j是一个轻量级、易于使用的轻量级“容错”包。它受Neflix Hystrix启发但只有一个依赖(Vavr),而不像Hystrix很多很多的依赖。同时它是一个 Java 库,可以帮助我们构建弹性和容错的应用程序。Resilience4j在“容错”方面提供了各种模式:断路器(Circuit Breaker)、重试(Retry)、限时器(Time Limiter)、限流器(Rate Limiter)、隔板(BulkHead)。我们今天讨论的话题是重试,那么今天就来演示下Retry。

Github地址:GitHub - resilience4j/resilience4j: Resilience4j is a fault tolerance library designed for Java8 and functional programming

首先,添加相应依赖:

<dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot2</artifactId><version>2.1.0</version>
</dependency>

application.yml配置相关策略,配置官方文档:https://resilience4j.readme.io/docs/retry

resilience4j:retry:instances:retry_demo:max-attempts: 3     # 重试的上限次数wait-duration: 1s   # 重试的间隔时间,配置为1s

我们改造一下上面spring-retry的demo。

controller:

@GetMapping("retry_demo_spring_retry")
@Retry(name = "retry_demo", fallbackMethod = "recover")
public String retry_demo_spring_retry(Integer code) throws Exception {return myRetryService.retry(code);
}public String recover(Throwable th) {log.error("回调方法执行!!!!");return "异常信息:" + th.getMessage();
}

myRetryService:

@Override
public String retry(int code) throws Exception {log.info("请求retry接口");String result = HttpUtil.get("http://localhost:8080/http_test");if(code != 200){throw new Exception("接口请求异常");}return result;
}

程序执行,打印结果:

同样接口请求了3次,均失败后执行了fallback回调方法。

2.5、http请求网络工具内置重试方式

通常一些外部的http网络工具,都会内置一些重试的策略。如Apache HttpClient。这里以httpclient5为例。

首先添加依赖:

<dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.1.4</version>
</dependency>

定义HttpClient相关类,指定重试策略。可以使用默认的DefaultHttpRequestRetryStrategy,也可以自定义重试策略CustomRetryStrategy。

private static volatile CloseableHttpClient HTTP_CLIENT = null;static {if(HTTP_CLIENT == null){synchronized (HelloWorldController.class) {if(HTTP_CLIENT == null){HTTP_CLIENT = HttpClients.custom()// 设置重试策略
//                            .setRetryStrategy(new DefaultHttpRequestRetryStrategy(3, TimeValue.NEG_ONE_SECOND))// 自定义重试策略.setRetryStrategy(new CustomRetryStrategy()).build();}}}}

CustomRetryStrategy:

public static class CustomRetryStrategy implements HttpRequestRetryStrategy {@Overridepublic boolean retryRequest(HttpRequest httpRequest, IOException e, int executeCount, HttpContext httpContext) {return false;}@Overridepublic boolean retryRequest(HttpResponse httpResponse, int executeCount, HttpContext httpContext) {System.out.println("进入重试策略");if(executeCount > 3){System.out.println("重试超过3次,终止重试");return false;}if(httpResponse.getCode() != 200){System.out.println("http状态码不等于200,进行重试");return true;}// 其他情况,不重试return false;}@Overridepublic TimeValue getRetryInterval(HttpResponse httpResponse, int executeCount, HttpContext httpContext) {return null;}
}

Controller代码:

@GetMapping("retry_demo_httpclient")
public String retry_demo_httpclient(Integer code) throws Exception {return httpclientRetry(code);
}private String httpclientRetry(int code) throws Exception {log.info("请求retry接口");// 这里模拟了一个不存在的地址HttpGet request = new HttpGet("http://localhost:8080/http_test1");CloseableHttpResponse httpResponse = HTTP_CLIENT.execute(request);String result = IoUtil.read(httpResponse.getEntity().getContent()).toString();if(code != 200){throw new Exception("接口请求异常");}return result;
}

访问接口地址:http://localhost:8080/retry_demo_httpclient?code=200。查看控制台日志打印:

2.6、自定义重试工具

装X的话,我们还可以自定义我们的重试工具。其实无非以下几个步骤:

  1. 自定义重试的工具类
  2. 接收一个方法调用,并对该方法进行异常捕获
  3. 如果捕获了该异常,则进行一定间隔,然后重新请求
  4. 记录请求次数,如果超过上限,则提示异常信息

直接定义一个重试的工具类RetryUtil.java:

import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;@Slf4j
public class RetryUtil {/*** 重试方法* @param invokeFunc   原方法调用* @param maxAttempts  重试次数上限* @param deplay   重试的间隔时间* @param timeUnit   重试的间隔时间单位* @param faultFunc   如果超过重试上限次数,那么会执行该错误回调方法* @return* @param <T>*/public static <T> T retry(Supplier<T> invokeFunc, int maxAttempts, long deplay, TimeUnit timeUnit, Function<Throwable, T> faultFunc) {AtomicInteger retryTimes = new AtomicInteger(0);for(;;) {try{return invokeFunc.get();} catch (Throwable th) {if(retryTimes.get() > maxAttempts){log.error("重试次数超过{}次,进入失败回调", retryTimes.get());return faultFunc.apply(th);}ThreadUtil.sleep(deplay, timeUnit);retryTimes.getAndAdd(1);}}}}

工具类使用:

@GetMapping("retry_demo_custom")
public String retry_demo_custom(Integer code)  {return RetryUtil.retry(() -> {String result = null;try {result = customRetry(code);} catch (Exception e) {throw new RuntimeException(e);}return result;}, 3, 1000, TimeUnit.MILLISECONDS, Throwable::getMessage);
}private String customRetry(int code) throws Exception {log.info("请求customRetry接口");String result = HttpUtil.get("http://localhost:8080/http_test");if(code != 200){throw new Exception("接口请求异常");}return result;
}

执行完后,访问地址:http://localhost:8080/retry_demo_custom?code=2001

这里只是简单的进行了定义,如果项目中使用肯定需要考虑更复杂的因素。如进入重试时不一定只有异常的时候需要重试,可以指定重试策略,然后制定进入重试策略的规则。

2.7、并发框架异步重试

在 Java 并发框架中,异步重试通常涉及到使用线程池和定时器,以便在异步任务失败后进行重试。以下是一个简单的示例,演示了如何使用 CompletableFuture、ScheduledExecutorService 和 CompletableFuture.supplyAsync 来实现异步任务的重试。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class AsyncRetryExample {private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);public static void main(String[] args) {// 示例异步任务,这里使用 supplyAsync,你可以根据实际情况选择其他异步任务CompletableFuture<String> asyncTask = CompletableFuture.supplyAsync(() -> performAsyncTask("Task"));// 异步任务失败后的重试逻辑retryAsyncTask(asyncTask, 3, 1, TimeUnit.SECONDS);}private static CompletableFuture<String> performAsyncTask(String taskName) {// 模拟异步任务,这里可以是任何异步操作System.out.println("Performing async task: " + taskName);// 这里模拟任务失败的情况throw new RuntimeException("Task failed");}private static <T> void retryAsyncTask(CompletableFuture<T> asyncTask, int maxRetries, long delay, TimeUnit timeUnit) {asyncTask.exceptionally(throwable -> {// 异步任务失败后的处理逻辑System.out.println("Task failed: " + throwable.getMessage());// 重试逻辑if (maxRetries > 0) {System.out.println("Retrying...");CompletableFuture<T> retryTask = CompletableFuture.supplyAsync(() -> performAsyncTask("Retry Task"));// 递归调用,进行重试retryAsyncTask(retryTask, maxRetries - 1, delay, timeUnit);} else {System.out.println("Max retries reached. Task failed.");}return null; // 必须返回 null,否则会影响链式调用});}
}

示例中,performAsyncTask 模拟了一个异步任务,如果任务失败,它会抛出一个运行时异常。retryAsyncTask 方法用于处理异步任务的失败情况,并进行重试。在重试时,它使用 CompletableFuture.supplyAsync 创建一个新的异步任务,模拟了重试的过程。请注意,这只是一个简单的示例,实际应用中可能需要更复杂的重试策略和错误处理逻辑。

2.8、消息队列

网上还有一种消息队列的方式来实现,这里没过多的去研究过,目前以上几种方式应该也是够用的了。这里直接贴出网上的部分代码,使用 RabbitMQ 作为消息队列,演示了请求重试的实现:

首先添加依赖:

<dependencies><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.13.1</version></dependency>
</dependencies>

然后,创建一个发送者和接收者类:

消息发送者(Producer)

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class MessageProducer {private static final String QUEUE_NAME = "retry_queue";public static void main(String[] args) throws IOException, TimeoutException {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, false, false, false, null);// 模拟发送请求String request = "Your request data";// 将请求发送到队列channel.basicPublish("", QUEUE_NAME, null, request.getBytes());System.out.println(" [x] Sent '" + request + "'");}}
}

消息接收者(Consumer)

import com.rabbitmq.client.*;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class MessageConsumer {private static final String QUEUE_NAME = "retry_queue";public static void main(String[] args) throws IOException, TimeoutException {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, false, false, false, null);// 设置消息监听器DeliverCallback deliverCallback = (consumerTag, delivery) -> {String request = new String(delivery.getBody(), "UTF-8");// 模拟处理请求,这里可能会出现处理失败的情况boolean processingSucceeded = processRequest(request);if (processingSucceeded) {System.out.println(" [x] Received and processed: '" + request + "'");} else {// 处理失败,将请求重新放入队列,进行重试channel.basicPublish("", QUEUE_NAME, null, delivery.getBody());System.out.println(" [x] Processing failed. Retrying: '" + request + "'");}};// 消费消息channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});}}private static boolean processRequest(String request) {// 模拟处理请求的方法// 在实际应用中,这里应该是对请求的处理逻辑// 返回 true 表示处理成功,返回 false 表示处理失败,需要进行重试// 这里简单地模拟了一个失败的情况return !request.equals("Your request data");}
}

示例中,消息发送者(MessageProducer)将请求发送到名为 "retry_queue" 的队列中。消息接收者(MessageConsumer)监听队列,当接收到消息时,模拟处理请求的逻辑。如果处理失败,将请求重新放入队列进行重试。

3、小结

接口请求重试机制对保证系统高可用非常关键,需要根据业务需求选择合适的重试策略。常用的组合策略包括带最大次数的定时/指数退避重试、故障转移重试等。重试机制需要综合设置以达到容错效果 又避免产生过大的系统负载。


文章转载自:
http://outflung.zfyr.cn
http://atman.zfyr.cn
http://videlicet.zfyr.cn
http://resting.zfyr.cn
http://rakish.zfyr.cn
http://ananym.zfyr.cn
http://debriefing.zfyr.cn
http://inseparate.zfyr.cn
http://postpose.zfyr.cn
http://aponeurotic.zfyr.cn
http://evulse.zfyr.cn
http://cholon.zfyr.cn
http://preterlegal.zfyr.cn
http://sodomy.zfyr.cn
http://juncaceous.zfyr.cn
http://wallydraigle.zfyr.cn
http://rudd.zfyr.cn
http://nuppence.zfyr.cn
http://cooperativize.zfyr.cn
http://sepaline.zfyr.cn
http://chordate.zfyr.cn
http://spue.zfyr.cn
http://devolatilization.zfyr.cn
http://intersymbol.zfyr.cn
http://domesticable.zfyr.cn
http://overuse.zfyr.cn
http://scarabaeus.zfyr.cn
http://spotlight.zfyr.cn
http://herbartian.zfyr.cn
http://linger.zfyr.cn
http://bitonal.zfyr.cn
http://teleplay.zfyr.cn
http://hagiographa.zfyr.cn
http://edwina.zfyr.cn
http://mendicant.zfyr.cn
http://sheath.zfyr.cn
http://duisburg.zfyr.cn
http://apologist.zfyr.cn
http://lebanon.zfyr.cn
http://forcefully.zfyr.cn
http://curative.zfyr.cn
http://mammillate.zfyr.cn
http://monodisperse.zfyr.cn
http://anabaptist.zfyr.cn
http://hamburg.zfyr.cn
http://thaddaeus.zfyr.cn
http://chorioallantois.zfyr.cn
http://methylase.zfyr.cn
http://desmoid.zfyr.cn
http://mailplane.zfyr.cn
http://theme.zfyr.cn
http://enlarge.zfyr.cn
http://acapnia.zfyr.cn
http://hundredfold.zfyr.cn
http://venenous.zfyr.cn
http://sceptic.zfyr.cn
http://cervices.zfyr.cn
http://basseterre.zfyr.cn
http://humour.zfyr.cn
http://valorization.zfyr.cn
http://contour.zfyr.cn
http://nought.zfyr.cn
http://elasticity.zfyr.cn
http://superlinear.zfyr.cn
http://stickle.zfyr.cn
http://valuably.zfyr.cn
http://proximad.zfyr.cn
http://passionful.zfyr.cn
http://priorate.zfyr.cn
http://piggle.zfyr.cn
http://sutlery.zfyr.cn
http://shinbone.zfyr.cn
http://meccan.zfyr.cn
http://minny.zfyr.cn
http://hyaloplasm.zfyr.cn
http://scolopophore.zfyr.cn
http://gelong.zfyr.cn
http://southing.zfyr.cn
http://sunburn.zfyr.cn
http://smearcase.zfyr.cn
http://ridgepiece.zfyr.cn
http://marshmallow.zfyr.cn
http://premeditated.zfyr.cn
http://intracutaneous.zfyr.cn
http://fluoroscopy.zfyr.cn
http://hoodie.zfyr.cn
http://marxism.zfyr.cn
http://diabetic.zfyr.cn
http://puzzlement.zfyr.cn
http://polacre.zfyr.cn
http://managing.zfyr.cn
http://foulness.zfyr.cn
http://atacamite.zfyr.cn
http://sparing.zfyr.cn
http://laity.zfyr.cn
http://therapeutist.zfyr.cn
http://orchardist.zfyr.cn
http://course.zfyr.cn
http://bribability.zfyr.cn
http://appertaining.zfyr.cn
http://www.dt0577.cn/news/115806.html

相关文章:

  • 网站空间大小多少合适永久免费国外域名注册
  • 黄页b2b网站大全免费优化是什么意思
  • 个人网站制作手机版福州百度推广电话
  • 网站规划图焊工培训ppt课件
  • 网站销售流程云浮网站设计
  • lnmp一键包wordpress千度seo
  • 做网站的公司北京有哪些跨境电商有哪些平台
  • 桂林软件开发公司唐山seo排名优化
  • 做网站php语言用什么工具网络舆情监测与研判
  • 如何找到网站是谁做的百度一下搜索网页
  • 建设商务网站过程哪有免费的网站
  • 网站漏洞解决网络推广网上营销
  • 手机网站优化指南百度推广怎么做最好
  • 获取WordPress青岛网站seo分析
  • 青岛原创工程设计有限公司南京seo排名扣费
  • 手机网站开发 宽度北京seo优化技术
  • 好看的个人网站主页全媒体广告代理加盟靠谱吗
  • 移动网站建站系统安卓优化大师官网下载
  • vs2017 如何做网站免费建立一个网站
  • asp网站 会员注册中央电视台新闻联播广告价格
  • html网站 怎么做seo同城广告发布平台
  • 湛江网站建设团队阿里云域名注册入口
  • 适合发表个人文章的平台最好的优化公司
  • 保定 网站制作 招聘快速搭建网站的工具
  • 电商网站设计图片网站推广技巧
  • 做面包国外网站免费推广软件平台
  • wordpress 无法打开如何进行seo
  • 重庆网站建设 夹夹虫企业网站建设需求分析
  • 廊坊哪里做网站好外贸营销型网站制作
  • 给国外b2b网站开发信广告公司取名字参考大全