欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?遠(yuǎn)程調(diào)用失敗重試的操作方法

 更新時(shí)間:2022年09月15日 09:26:50   作者:鴨血粉絲Tang  
這篇文章主要介紹了Java?遠(yuǎn)程調(diào)用失敗重試的操作方法,今天給大家介紹了一下?Spring??的?@Retryable?注解使用,并通過(guò)幾個(gè) demo 來(lái)帶大家編寫(xiě)了自己重試攔截器以及回滾方法,需要的朋友可以參考下

在日常開(kāi)發(fā)的過(guò)程中我們經(jīng)常會(huì)需要調(diào)用第三方組件或者數(shù)據(jù)庫(kù),有的時(shí)候可能會(huì)因?yàn)榫W(wǎng)絡(luò)抖動(dòng)或者下游服務(wù)抖動(dòng),導(dǎo)致我們某次查詢(xún)失敗。

這種時(shí)候我們往往就會(huì)進(jìn)行重試,當(dāng)重試幾次后依舊還是失敗的話(huà)才會(huì)向上拋出異常進(jìn)行失敗。接下來(lái)阿粉就給大家演示一下通常是如何做的,以及如何更優(yōu)雅的進(jìn)行重試。

常規(guī)做法

我們先來(lái)看一下常規(guī)做法,常規(guī)做法首先會(huì)設(shè)置一個(gè)重試次數(shù),然后通過(guò) while 循環(huán)的方式進(jìn)行遍歷,當(dāng)循環(huán)次數(shù)沒(méi)有達(dá)到重試次數(shù)的時(shí)候,直到有正確結(jié)果后就返回,如果重試依舊失敗則會(huì)進(jìn)行睡眠一段時(shí)間,再次重試,直到正常返回或者達(dá)到重試次數(shù)返回。

package com.example.demo.service;

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class HelloService {
  public String sayHello(String name) {
    String result = "";
    int retryTime = 3;
    while (retryTime > 0) {
      try {
        //
        result = name + doSomething();
        return result;
      } catch (Exception e) {
        System.out.println("send message failed. try again in 1's");
        retryTime--;
        try {
          TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException ex) {
          throw new RuntimeException(ex);
        }
      }
    }
    return result;
  }

  private int doSomething() {
    Random random = new Random();
    int i = random.nextInt(3);
    System.out.println("i is " + i);
    return 10 / i;
  }
}

這里為了模擬異常的情況,阿粉在 doSomething? 函數(shù)里面進(jìn)行了隨機(jī)數(shù)的生成和使用,當(dāng)隨機(jī)出來(lái)的值為 0 的時(shí)候,則會(huì)觸發(fā) java.lang.ArithmeticException 異常,因?yàn)?0 不能作除數(shù)。

接下來(lái)我們?cè)賹?duì)外提供一個(gè)接口用于訪(fǎng)問(wèn),代碼如下

package com.example.demo.controller;

import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

  @Autowired
  private HelloService helloService;

  @GetMapping(value = "/hello")
  public String hello(@RequestParam("name") String name) {
    return helloService.sayHello(name);
  }
}

正常啟動(dòng)過(guò)后,我們通過(guò)瀏覽器進(jìn)行訪(fǎng)問(wèn)。

可以看到,我們第一次方法的時(shí)候就成功的達(dá)到了我們要的效果,隨機(jī)數(shù)就是 0 ,在 1 秒后重試后結(jié)果正常。在多試了幾次過(guò)后,會(huì)遇到三次都是 0 的情況,這個(gè)時(shí)候才會(huì)拋出異常,說(shuō)明服務(wù)是真的有問(wèn)題了。

上面的代碼可以看到是有效果了,雖然不是很好看,特別是在還有一些其他邏輯的情況,看上去會(huì)很臃腫,但是確實(shí)是可以正常使用的,那么有的小伙伴就要問(wèn)了,有沒(méi)有一種優(yōu)雅的方式呢?總不能在很多地方都重復(fù)的這樣寫(xiě)重試的代碼吧。

注解重試

要知道我們普通人在日常開(kāi)發(fā)的時(shí)候,如果遇到一個(gè)問(wèn)題肯定是別人都遇到過(guò)的,什么時(shí)候當(dāng)我們遇到的問(wèn)題,沒(méi)有人遇到過(guò)的時(shí)候,那說(shuō)明我們是很前衛(wèi)的。

因此小伙伴能想到的是不是有簡(jiǎn)單的方式來(lái)進(jìn)行重試,有的人已經(jīng)幫我們想好了,可以通過(guò) @Retryable 注解來(lái)實(shí)現(xiàn)一樣的效果,接下來(lái)阿粉就給大家演示一下如何使用這個(gè)注解。

首先我們需要在啟動(dòng)類(lèi)上面加入 @EnableRetry? 注解,表示要開(kāi)啟重試的功能,這個(gè)很好理解,就像我們要開(kāi)啟定時(shí)功能需要添加 @EnableScheduling? 注解一樣,Spring? 的 @Enablexxx 注解也是很有意思的,后面我們?cè)倭摹?/p>

添加完注解以后,需要加入切面的依賴(lài),如下

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.2</version>
</dependency>

如下不加入這個(gè)切面依賴(lài),啟動(dòng)的時(shí)候會(huì)有如下異常

添加的注解和依賴(lài)過(guò)后,我們需要改造 HelloService? 里面的 sayHello()? 方法,簡(jiǎn)化成如下,增加  @Retryable 注解,以及設(shè)置相應(yīng)的參數(shù)值。

@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2))
  public String sayHello(String name){
    return name + doSomething();
  }

再次通過(guò)瀏覽器訪(fǎng)問(wèn) http://127.0.0.1:8080/hello?name=ziyou 我們看到效果如下,跟我們自己寫(xiě)的重試一樣。

@Retryable 詳解

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.retry.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Retryable {
    String recover() default "";

    String interceptor() default "";

    Class<? extends Throwable>[] value() default {};

    Class<? extends Throwable>[] include() default {};

    Class<? extends Throwable>[] exclude() default {};

    String label() default "";

    boolean stateful() default false;

    int maxAttempts() default 3;

    String maxAttemptsExpression() default "";

    Backoff backoff() default @Backoff;

    String exceptionExpression() default "";

    String[] listeners() default {};
}

點(diǎn)到這個(gè)注解里面,我們可以看到這個(gè)注解的代碼如下,其中有幾個(gè)參數(shù)我們來(lái)解釋一下

  • recover:  當(dāng)前類(lèi)中的回滾方法名稱(chēng);
  • interceptor: 重試的攔截器名稱(chēng),重試的時(shí)候可以配置一個(gè)攔截器;
  • value:需要重試的異常類(lèi)型,跟下面的 include 一致;
  • include:包含的重試的異常類(lèi)型;
  • exclude:不包含的重試異常類(lèi)型;
  • label:用于統(tǒng)計(jì)的唯一標(biāo)識(shí);
  • stateful?:標(biāo)志表示重試是有狀態(tài)的,也就是說(shuō),異常被重新拋出,重試策略是否會(huì)以相同的策略應(yīng)用于具有相同參數(shù)的后續(xù)調(diào)用。如果是false,那么可重試的異常就不會(huì)被重新拋出。
  • maxAttempts:重試次數(shù);
  • backoff:指定用于重試此操作的屬性;
  • listeners?:重試監(jiān)聽(tīng)器bean 名稱(chēng);

配合上面的一些屬性的使用,我們就可以達(dá)到通過(guò)注解簡(jiǎn)單來(lái)實(shí)現(xiàn)方法調(diào)用異常后的自動(dòng)重試,非常好用。我們可以在執(zhí)行重試方法的時(shí)候設(shè)置自定義的重試攔截器,如下所示,自定義重試攔截器需要實(shí)現(xiàn) MethodInterceptor? 接口并實(shí)現(xiàn) invoke 方法,不過(guò)要注意,如果使用了攔截器的話(huà),那么方法上的參數(shù)就會(huì)被覆蓋。

package com.example.demo.pid;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.stereotype.Component;

@Component
public class CustomRetryInterceptor implements MethodInterceptor {

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    RetryOperationsInterceptor build = RetryInterceptorBuilder.stateless()
      .maxAttempts(2).backOffOptions(3000, 2, 1000).build();
    return build.invoke(invocation);
  }
}

自定義回滾方法,我們還可以在重試幾次依舊錯(cuò)誤的情況,編寫(xiě)自定義的回滾方法。

@Retryable(value = Exception.class,
    recover = "recover", maxAttempts = 2,
    backoff = @Backoff(delay = 1000, multiplier = 2))
  public String sayHello(String name){
    return name + doSomething();
  }

  @Recover
  public String recover(Exception e, String name) {
    System.out.println("recover");
    return "recover";
  }

要注意:

  • 重試方法必須要使用@Recover 注解;
  • 返回值必須和被重試的函數(shù)返回值一致;
  • 參數(shù)中除了第一個(gè)是觸發(fā)的異常外,后面的參數(shù)需要和被重試函數(shù)的參數(shù)列表一致;

上面代碼中的 @Backoff(delay = 1000, multiplier = 2) 表示第一次延遲 1000ms 重試,后面每次重試的延遲時(shí)間都翻倍。

總結(jié)

阿粉今天給大家介紹了一下 Spring? 的 @Retryable 注解使用,并通過(guò)幾個(gè) demo 來(lái)帶大家編寫(xiě)了自己重試攔截器以及回滾方法的時(shí)候,是不是感覺(jué)用起來(lái)會(huì)很爽,那還在等什么趕緊用起來(lái)吧,其中還有很多細(xì)節(jié),只有自己真正的使用過(guò)才能體會(huì)到。

到此這篇關(guān)于Java 遠(yuǎn)程調(diào)用失敗重試的操作方法的文章就介紹到這了,更多相關(guān)Java 遠(yuǎn)程調(diào)用失敗內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 學(xué)習(xí)SpringMVC——國(guó)際化+上傳+下載詳解

    學(xué)習(xí)SpringMVC——國(guó)際化+上傳+下載詳解

    本篇文章主要介紹了學(xué)習(xí)SpringMVC——國(guó)際化+上傳+下載,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。
    2016-12-12
  • Spring @Cacheable注解中key的使用詳解

    Spring @Cacheable注解中key的使用詳解

    這篇文章主要介紹了Spring @Cacheable注解中key的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • spring boot實(shí)現(xiàn)軟刪除的示例代碼

    spring boot實(shí)現(xiàn)軟刪除的示例代碼

    這篇文章主要介紹了spring boot實(shí)現(xiàn)軟刪除的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • 詳解Java中異步轉(zhuǎn)同步的六種方法

    詳解Java中異步轉(zhuǎn)同步的六種方法

    針對(duì)應(yīng)用中異步調(diào)用,能不能像同步調(diào)用一樣立刻獲取到命令的執(zhí)行結(jié)果,如何實(shí)現(xiàn)異步轉(zhuǎn)同步?不要擔(dān)心,本文就來(lái)為大家詳細(xì)講講Java中異步轉(zhuǎn)同步的六種方法,感興趣的可以了解一下
    2022-06-06
  • 簡(jiǎn)單操作實(shí)現(xiàn)Java jsp servlet文件上傳過(guò)程解析

    簡(jiǎn)單操作實(shí)現(xiàn)Java jsp servlet文件上傳過(guò)程解析

    這篇文章主要介紹了簡(jiǎn)單操作實(shí)現(xiàn)Java jsp servlet文件上傳過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • IDEA 開(kāi)發(fā)多項(xiàng)目依賴(lài)的方法(圖文)

    IDEA 開(kāi)發(fā)多項(xiàng)目依賴(lài)的方法(圖文)

    這篇文章主要介紹了IDEA 開(kāi)發(fā)多項(xiàng)目依賴(lài)的方法(圖文),本文講一下關(guān)于使用IntelliJ IDEA基于Maven創(chuàng)建多模塊項(xiàng)目的實(shí)際開(kāi)發(fā),非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-10-10
  • 解決IDEA Gradle構(gòu)建報(bào)錯(cuò)''Cause: zip END header not found''

    解決IDEA Gradle構(gòu)建報(bào)錯(cuò)''Cause: zip END header not found''

    這篇文章主要介紹了解決IDEA Gradle構(gòu)建報(bào)錯(cuò)"Cause: zip END header not found"的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Java遞歸實(shí)現(xiàn)迷宮游戲

    Java遞歸實(shí)現(xiàn)迷宮游戲

    這篇文章主要介紹了如何利用Java遞歸方法實(shí)現(xiàn)迷宮游戲,下面文章會(huì)詳細(xì)的從為問(wèn)題描述開(kāi)始,清晰的解題思路以及詳細(xì)的代碼實(shí)現(xiàn),具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2021-12-12
  • 基于java中正則操作的方法總結(jié)

    基于java中正則操作的方法總結(jié)

    本篇文章介紹了,在java中正則操作的方法總結(jié)。需要的朋友參考下
    2013-05-05
  • SpringBoot路徑映射實(shí)現(xiàn)過(guò)程圖解

    SpringBoot路徑映射實(shí)現(xiàn)過(guò)程圖解

    這篇文章主要介紹了SpringBoot路徑映射實(shí)現(xiàn)過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12

最新評(píng)論