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

深入淺出Java中重試機(jī)制的多種方式

 更新時(shí)間:2023年03月14日 10:15:43   作者:Yubaba丶  
重試機(jī)制在分布式系統(tǒng)中,或者調(diào)用外部接口中,都是十分重要的。重試機(jī)制可以保護(hù)系統(tǒng)減少因網(wǎng)絡(luò)波動(dòng)、依賴服務(wù)短暫性不可用帶來(lái)的影響,讓系統(tǒng)能更穩(wěn)定的運(yùn)行的一種保護(hù)機(jī)制。本文就來(lái)和大家聊聊Java中重試機(jī)制的多種方式

重試機(jī)制在分布式系統(tǒng)中,或者調(diào)用外部接口中,都是十分重要的。

重試機(jī)制可以保護(hù)系統(tǒng)減少因網(wǎng)絡(luò)波動(dòng)、依賴服務(wù)短暫性不可用帶來(lái)的影響,讓系統(tǒng)能更穩(wěn)定的運(yùn)行的一種保護(hù)機(jī)制。

為了方便說(shuō)明,先假設(shè)我們想要進(jìn)行重試的方法如下:

@Slf4j
@Component
public class HelloService {
 
    private static AtomicLong helloTimes = new AtomicLong();
 
    public String hello(){
        long times = helloTimes.incrementAndGet();
        if (times % 4 != 0){
            log.warn("發(fā)生異常,time:{}", LocalTime.now() );
            throw new HelloRetryException("發(fā)生Hello異常");
        }
        return "hello";
    }
}

調(diào)用處:

@Slf4j
@Service
public class HelloRetryService implements IHelloService{
 
    @Autowired
    private HelloService helloService;
 
    public String hello(){
        return helloService.hello();
    }
}

也就是說(shuō),這個(gè)接口每調(diào)4次才會(huì)成功一次。

1.手動(dòng)重試

先來(lái)用最簡(jiǎn)單的方法,直接在調(diào)用的時(shí)候進(jìn)重試:

// 手動(dòng)重試
public String hello(){
    int maxRetryTimes = 4;
    String s = "";
    for (int retry = 1; retry <= maxRetryTimes; retry++) {
        try {
            s = helloService.hello();
            log.info("helloService返回:{}", s);
            return s;
        } catch (HelloRetryException e) {
            log.info("helloService.hello() 調(diào)用失敗,準(zhǔn)備重試");
        }
    }
    throw new HelloRetryException("重試次數(shù)耗盡");
}

發(fā)生異常,time:10:17:21.079413300
helloService.hello() 調(diào)用失敗,準(zhǔn)備重試
發(fā)生異常,time:10:17:21.085861800
helloService.hello() 調(diào)用失敗,準(zhǔn)備重試
發(fā)生異常,time:10:17:21.085861800
helloService.hello() 調(diào)用失敗,準(zhǔn)備重試
helloService返回:hello
service.helloRetry():hello

程序在極短的時(shí)間內(nèi)進(jìn)行了4次重試,然后成功返回。

這樣雖然看起來(lái)可以解決問(wèn)題,但實(shí)踐上,由于沒(méi)有重試間隔,很可能當(dāng)時(shí)依賴的服務(wù)尚未從網(wǎng)絡(luò)異常中恢復(fù)過(guò)來(lái),所以極有可能接下來(lái)的幾次調(diào)用都是失敗的。

而且,這樣需要對(duì)代碼進(jìn)行大量的侵入式修改,顯然,不優(yōu)雅。

2.代理模式

上面的處理方式由于需要對(duì)業(yè)務(wù)代碼進(jìn)行大量修改,雖然實(shí)現(xiàn)了功能,但是對(duì)原有代碼的侵入性太強(qiáng),可維護(hù)性差。

所以需要使用一種更優(yōu)雅一點(diǎn)的方式,不直接修改業(yè)務(wù)代碼,那要怎么做呢?

其實(shí)很簡(jiǎn)單,直接在業(yè)務(wù)代碼的外面再包一層就行了,代理模式在這里就有用武之地了。你會(huì)發(fā)現(xiàn)又是代理。

@Slf4j
public class HelloRetryProxyService implements IHelloService{
   
    @Autowired
    private HelloRetryService helloRetryService;
    
    @Override
    public String hello() {
        int maxRetryTimes = 4;
        String s = "";
        for (int retry = 1; retry <= maxRetryTimes; retry++) {
            try {
                s = helloRetryService.hello();
                log.info("helloRetryService 返回:{}", s);
                return s;
            } catch (HelloRetryException e) {
                log.info("helloRetryService.hello() 調(diào)用失敗,準(zhǔn)備重試");
            }
        }
        throw new HelloRetryException("重試次數(shù)耗盡");
    }
}

這樣,重試邏輯就都由代理類(lèi)來(lái)完成,原業(yè)務(wù)類(lèi)的邏輯就不需要修改了,以后想修改重試邏輯也只需要修改這個(gè)類(lèi)就行了,分工明確。比如,現(xiàn)在想要在重試之間加上一個(gè)延遲,只需要做一點(diǎn)點(diǎn)修改即可:

@Override
public String hello() {
    int maxRetryTimes = 4;
    String s = "";
    for (int retry = 1; retry <= maxRetryTimes; retry++) {
        try {
            s = helloRetryService.hello();
            log.info("helloRetryService 返回:{}", s);
            return s;
        } catch (HelloRetryException e) {
            log.info("helloRetryService.hello() 調(diào)用失敗,準(zhǔn)備重試");
        }
        // 延時(shí)一秒
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    throw new HelloRetryException("重試次數(shù)耗盡");
}

代理模式雖然要更加優(yōu)雅,但是如果依賴的服務(wù)很多的時(shí)候,要為每個(gè)服務(wù)都創(chuàng)建一個(gè)代理類(lèi),顯然過(guò)于麻煩,而且其實(shí)重試的邏輯都大同小異,無(wú)非就是重試的次數(shù)和延時(shí)不一樣而已。

如果每個(gè)類(lèi)都寫(xiě)這么一長(zhǎng)串類(lèi)似的代碼,顯然,不優(yōu)雅!

3.JDK動(dòng)態(tài)代理

這時(shí)候,動(dòng)態(tài)代理就閃亮登場(chǎng)了。只需要寫(xiě)一個(gè)代理處理類(lèi)就ok了。

@Slf4j
public class RetryInvocationHandler implements InvocationHandler {
 
    private final Object subject;
 
    public RetryInvocationHandler(Object subject) {
        this.subject = subject;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        int times = 0;
 
        while (times < RetryConstant.MAX_TIMES) {
            try {
                return method.invoke(subject, args);
            } catch (Exception e) {
                times++;
                log.info("times:{},time:{}", times, LocalTime.now());
                if (times >= RetryConstant.MAX_TIMES) {
                    throw new RuntimeException(e);
                }
            }
 
            // 延時(shí)一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
 
        return null;
    }
 
    /**
     * 獲取動(dòng)態(tài)代理
     *
     * @param realSubject 代理對(duì)象
     */
    public static Object getProxy(Object realSubject) {
        InvocationHandler handler = new RetryInvocationHandler(realSubject);
        return Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);
    }
 
}

咱們測(cè)試一下:

@Test
public void helloDynamicProxy() {
    IHelloService realService = new HelloService();
    IHelloService proxyService = (IHelloService)RetryInvocationHandler.getProxy(realService);
 
    String hello = proxyService.hello();
    log.info("hello:{}", hello);
}

輸出結(jié)果如下:

hello times:1
發(fā)生異常,time:11:22:20.727586700
times:1,time:11:22:20.728083
hello times:2
發(fā)生異常,time:11:22:21.728858700
times:2,time:11:22:21.729343700
hello times:3
發(fā)生異常,time:11:22:22.729706600
times:3,time:11:22:22.729706600
hello times:4
hello:hello

在重試了4次之后輸出了Hello,符合預(yù)期。

動(dòng)態(tài)代理可以將重試邏輯都放到一塊,顯然比直接使用代理類(lèi)要方便很多,也更加優(yōu)雅。

不過(guò)不要高興的太早,這里因?yàn)楸淮淼腍elloService是一個(gè)簡(jiǎn)單的類(lèi),沒(méi)有依賴其它類(lèi),所以直接創(chuàng)建是沒(méi)有問(wèn)題的,但如果被代理的類(lèi)依賴了其它被Spring容器管理的類(lèi),則這種方式會(huì)拋出異常,因?yàn)闆](méi)有把被依賴的實(shí)例注入到創(chuàng)建的代理實(shí)例中。

這種情況下,就比較復(fù)雜了,需要從Spring容器中獲取已經(jīng)裝配好的,需要被代理的實(shí)例,然后為其創(chuàng)建代理類(lèi)實(shí)例,并交給Spring容器來(lái)管理,這樣就不用每次都重新創(chuàng)建新的代理類(lèi)實(shí)例了。

話不多說(shuō),擼起袖子就是干。

新建一個(gè)工具類(lèi),用來(lái)獲取代理實(shí)例:

@Component
public class RetryProxyHandler {
 
    @Autowired
    private ConfigurableApplicationContext context;
 
    public Object getProxy(Class clazz) {
        // 1. 從Bean中獲取對(duì)象
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getAutowireCapableBeanFactory();
        Map<String, Object> beans = beanFactory.getBeansOfType(clazz);
        Set<Map.Entry<String, Object>> entries = beans.entrySet();
        if (entries.size() <= 0){
            throw new ProxyBeanNotFoundException();
        }
        // 如果有多個(gè)候選bean, 判斷其中是否有代理bean
        Object bean = null;
        if (entries.size() > 1){
            for (Map.Entry<String, Object> entry : entries) {
                if (entry.getKey().contains(PROXY_BEAN_SUFFIX)){
                    bean = entry.getValue();
                }
            };
            if (bean != null){
                return bean;
            }
            throw new ProxyBeanNotSingleException();
        }
 
        Object source = beans.entrySet().iterator().next().getValue();
        Object source = beans.entrySet().iterator().next().getValue();
 
        // 2. 判斷該對(duì)象的代理對(duì)象是否存在
        String proxyBeanName = clazz.getSimpleName() + PROXY_BEAN_SUFFIX;
        Boolean exist = beanFactory.containsBean(proxyBeanName);
        if (exist) {
            bean = beanFactory.getBean(proxyBeanName);
            return bean;
        }
 
        // 3. 不存在則生成代理對(duì)象
        bean = RetryInvocationHandler.getProxy(source);
 
        // 4. 將bean注入spring容器
        beanFactory.registerSingleton(proxyBeanName, bean);
        return bean;
    }
}

使用的是JDK動(dòng)態(tài)代理:

@Slf4j
public class RetryInvocationHandler implements InvocationHandler {
 
    private final Object subject;
 
    public RetryInvocationHandler(Object subject) {
        this.subject = subject;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        int times = 0;
 
        while (times < RetryConstant.MAX_TIMES) {
            try {
                return method.invoke(subject, args);
            } catch (Exception e) {
                times++;
                log.info("retry times:{},time:{}", times, LocalTime.now());
                if (times >= RetryConstant.MAX_TIMES) {
                    throw new RuntimeException(e);
                }
            }
 
            // 延時(shí)一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
 
        return null;
    }
 
    /**
     * 獲取動(dòng)態(tài)代理
     *
     * @param realSubject 代理對(duì)象
     */
    public static Object getProxy(Object realSubject) {
        InvocationHandler handler = new RetryInvocationHandler(realSubject);
        return Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);
    }
 
}

至此,主要代碼就完成了,修改一下HelloService類(lèi),增加一個(gè)依賴:

@Slf4j
@Component
public class HelloService implements IHelloService{
 
    private static AtomicLong helloTimes = new AtomicLong();
 
    @Autowired
    private NameService nameService;
 
    public String hello(){
        long times = helloTimes.incrementAndGet();
        log.info("hello times:{}", times);
        if (times % 4 != 0){
            log.warn("發(fā)生異常,time:{}", LocalTime.now() );
            throw new HelloRetryException("發(fā)生Hello異常");
        }
        return "hello " + nameService.getName();
    }
}

NameService其實(shí)很簡(jiǎn)單,創(chuàng)建的目的僅在于測(cè)試依賴注入的Bean能否正常運(yùn)行。

@Service
public class NameService {
 
    public String getName(){
        return "Frank";
    }
}

測(cè)試一下:

@Test
public void helloJdkProxy() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
    IHelloService proxy = (IHelloService) retryProxyHandler.getProxy(HelloService.class);
    String hello = proxy.hello();
    log.info("hello:{}", hello);
}

結(jié)果:

hello times:1
發(fā)生異常,time:14:40:27.540672200
retry times:1,time:14:40:27.541167400
hello times:2
發(fā)生異常,time:14:40:28.541584600
retry times:2,time:14:40:28.542033500
hello times:3
發(fā)生異常,time:14:40:29.542161500
retry times:3,time:14:40:29.542161500
hello times:4
hello:hello Frank

完美,這樣就不用擔(dān)心依賴注入的問(wèn)題了,因?yàn)閺腟pring容器中拿到的Bean對(duì)象都是已經(jīng)注入配置好的。當(dāng)然,這里僅考慮了單例Bean的情況,可以考慮的更加完善一點(diǎn),判斷一下容器中Bean的類(lèi)型是Singleton還是Prototype,如果是Singleton則像上面這樣進(jìn)行操作,如果是Prototype則每次都新建代理類(lèi)對(duì)象。

另外,這里使用的是JDK動(dòng)態(tài)代理,因此就存在一個(gè)天然的缺陷,如果想要被代理的類(lèi),沒(méi)有實(shí)現(xiàn)任何接口,那么就無(wú)法為其創(chuàng)建代理對(duì)象,這種方式就行不通了。

4.Spring AOP

想要無(wú)侵入式的修改原有邏輯?想要一個(gè)注解就實(shí)現(xiàn)重試?用Spring AOP不就能完美實(shí)現(xiàn)嗎?使用AOP來(lái)為目標(biāo)調(diào)用設(shè)置切面,即可在目標(biāo)方法調(diào)用前后添加一些額外的邏輯。

先創(chuàng)建一個(gè)注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Retryable {
    int retryTimes() default 3;
    int retryInterval() default 1;
}

有兩個(gè)參數(shù),retryTimes 代表最大重試次數(shù),retryInterval代表重試間隔。

@Retryable(retryTimes = 4, retryInterval = 2)
public String hello(){
    long times = helloTimes.incrementAndGet();
    log.info("hello times:{}", times);
    if (times % 4 != 0){
        log.warn("發(fā)生異常,time:{}", LocalTime.now() );
        throw new HelloRetryException("發(fā)生Hello異常");
    }
    return "hello " + nameService.getName();
}

接著,進(jìn)行最后一步,編寫(xiě)AOP切面:

@Slf4j
@Aspect
@Component
public class RetryAspect {
 
    @Pointcut("@annotation(com.mfrank.springboot.retry.demo.annotation.Retryable)")
    private void retryMethodCall(){}
 
    @Around("retryMethodCall()")
    public Object retry(ProceedingJoinPoint joinPoint) throws InterruptedException {
        // 獲取重試次數(shù)和重試間隔
        Retryable retry = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(Retryable.class);
        int maxRetryTimes = retry.retryTimes();
        int retryInterval = retry.retryInterval();
 
        Throwable error = new RuntimeException();
        for (int retryTimes = 1; retryTimes <= maxRetryTimes; retryTimes++){
            try {
                Object result = joinPoint.proceed();
                return result;
            } catch (Throwable throwable) {
                error = throwable;
                log.warn("調(diào)用發(fā)生異常,開(kāi)始重試,retryTimes:{}", retryTimes);
            }
            Thread.sleep(retryInterval * 1000);
        }
        throw new RetryExhaustedException("重試次數(shù)耗盡", error);
    }
}

開(kāi)始測(cè)試:

@Autowired
private HelloService helloService;
 
@Test
public void helloAOP(){
    String hello = helloService.hello();
    log.info("hello:{}", hello);
}

打印結(jié)果:

hello times:1
發(fā)生異常,time:16:49:30.224649800
調(diào)用發(fā)生異常,開(kāi)始重試,retryTimes:1
hello times:2
發(fā)生異常,time:16:49:32.225230800
調(diào)用發(fā)生異常,開(kāi)始重試,retryTimes:2
hello times:3
發(fā)生異常,time:16:49:34.225968900
調(diào)用發(fā)生異常,開(kāi)始重試,retryTimes:3
hello times:4
hello:hello Frank

這樣就相當(dāng)優(yōu)雅了,一個(gè)注解就能搞定重試,簡(jiǎn)直不要更棒。

5.Spring 的重試注解

實(shí)際上Spring中就有比較完善的重試機(jī)制,比上面的切面更加好用,還不需要自己動(dòng)手重新造輪子。

那讓我們先來(lái)看看這個(gè)輪子究竟好不好使。

先引入重試所需的jar包:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

然后在啟動(dòng)類(lèi)或者配置類(lèi)上添加@EnableRetry注解,接下來(lái)在需要重試的方法上添加@Retryable注解(嗯?好像跟我自定義的注解一樣?竟然抄襲我的注解【手動(dòng)狗頭】)

@Retryable
public String hello(){
    long times = helloTimes.incrementAndGet();
    log.info("hello times:{}", times);
    if (times % 4 != 0){
        log.warn("發(fā)生異常,time:{}", LocalTime.now() );
        throw new HelloRetryException("發(fā)生Hello異常");
    }
    return "hello " + nameService.getName();
}

默認(rèn)情況下,會(huì)重試三次,重試間隔為1秒。當(dāng)然我們也可以自定義重試次數(shù)和間隔。這樣就跟我前面實(shí)現(xiàn)的功能是一毛一樣的了。

但Spring里的重試機(jī)制還支持很多很有用的特性,比如說(shuō),可以指定只對(duì)特定類(lèi)型的異常進(jìn)行重試,這樣如果拋出的是其它類(lèi)型的異常則不會(huì)進(jìn)行重試,就可以對(duì)重試進(jìn)行更細(xì)粒度的控制。默認(rèn)為空,會(huì)對(duì)所有異常都重試。

@Retryable{value = {HelloRetryException.class}}
public String hello(){
    ...
}

也可以使用include和exclude來(lái)指定包含或者排除哪些異常進(jìn)行重試。

可以用maxAttemps指定最大重試次數(shù),默認(rèn)為3次。

可以用interceptor設(shè)置重試攔截器的bean名稱(chēng)。

可以通過(guò)label設(shè)置該重試的唯一標(biāo)志,用于統(tǒng)計(jì)輸出。

可以使用exceptionExpression來(lái)添加異常表達(dá)式,在拋出異常后執(zhí)行,以判斷后續(xù)是否進(jìn)行重試。

此外,Spring中的重試機(jī)制還支持使用backoff來(lái)設(shè)置重試補(bǔ)償機(jī)制,可以設(shè)置重試間隔,并且支持設(shè)置重試延遲倍數(shù)。

舉個(gè)例子:

@Retryable(value = {HelloRetryException.class}, maxAttempts = 5,
           backoff = @Backoff(delay = 1000, multiplier = 2))
public String hello(){
    ...
}

該方法調(diào)用將會(huì)在拋出HelloRetryException異常后進(jìn)行重試,最大重試次數(shù)為5,第一次重試間隔為1s,之后以2倍大小進(jìn)行遞增,第二次重試間隔為2s,第三次為4s,第四次為8s。

重試機(jī)制還支持使用@Recover 注解來(lái)進(jìn)行善后工作,當(dāng)重試達(dá)到指定次數(shù)之后,將會(huì)調(diào)用該方法,可以在該方法中進(jìn)行日志記錄等操作。

這里值得注意的是,想要@Recover 注解生效的話,需要跟被@Retryable 標(biāo)記的方法在同一個(gè)類(lèi)中,且被@Retryable 標(biāo)記的方法不能有返回值,否則不會(huì)生效。

并且如果使用了@Recover注解的話,重試次數(shù)達(dá)到最大次數(shù)后,如果在@Recover標(biāo)記的方法中無(wú)異常拋出,是不會(huì)拋出原異常的。

@Recover
public boolean recover(Exception e) {
    log.error("達(dá)到最大重試次數(shù)",e);
    return false;
}

除了使用注解外,Spring Retry 也支持直接在調(diào)用時(shí)使用代碼進(jìn)行重試:

@Test
public void normalSpringRetry() {
    // 表示哪些異常需要重試,key表示異常的字節(jié)碼,value為true表示需要重試
    Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
    exceptionMap.put(HelloRetryException.class, true);
 
    // 構(gòu)建重試模板實(shí)例
    RetryTemplate retryTemplate = new RetryTemplate();
 
    // 設(shè)置重試回退操作策略,主要設(shè)置重試間隔時(shí)間
    FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
    long fixedPeriodTime = 1000L;
    backOffPolicy.setBackOffPeriod(fixedPeriodTime);
 
    // 設(shè)置重試策略,主要設(shè)置重試次數(shù)
    int maxRetryTimes = 3;
    SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
 
    retryTemplate.setRetryPolicy(retryPolicy);
    retryTemplate.setBackOffPolicy(backOffPolicy);
 
    Boolean execute = retryTemplate.execute(
        //RetryCallback
        retryContext -> {
            String hello = helloService.hello();
            log.info("調(diào)用的結(jié)果:{}", hello);
            return true;
        },
        // RecoverCallBack
        retryContext -> {
            //RecoveryCallback
            log.info("已達(dá)到最大重試次數(shù)");
            return false;
        }
    );
}

此時(shí)唯一的好處是可以設(shè)置多種重試策略:

  • NeverRetryPolicy:只允許調(diào)用RetryCallback一次,不允許重試
  • AlwaysRetryPolicy:允許無(wú)限重試,直到成功,此方式邏輯不當(dāng)會(huì)導(dǎo)致死循環(huán)
  • SimpleRetryPolicy:固定次數(shù)重試策略,默認(rèn)重試最大次數(shù)為3次,RetryTemplate默認(rèn)使用的策略
  • TimeoutRetryPolicy:超時(shí)時(shí)間重試策略,默認(rèn)超時(shí)時(shí)間為1秒,在指定的超時(shí)時(shí)間內(nèi)允許重試
  • ExceptionClassifierRetryPolicy:設(shè)置不同異常的重試策略,類(lèi)似組合重試策略,區(qū)別在于這里只區(qū)分不同異常的重試
  • CircuitBreakerRetryPolicy:有熔斷功能的重試策略,需設(shè)置3個(gè)參數(shù)openTimeout、resetTimeout和delegate
  • CompositeRetryPolicy:組合重試策略,有兩種組合方式,樂(lè)觀組合重試策略是指只要有一個(gè)策略允許即可以重試,

悲觀組合重試策略是指只要有一個(gè)策略不允許即可以重試,但不管哪種組合方式,組合中的每一個(gè)策略都會(huì)執(zhí)行

可以看出,Spring中的重試機(jī)制還是相當(dāng)完善的,比上面自己寫(xiě)的AOP切面功能更加強(qiáng)大。

這里還需要再提醒的一點(diǎn)是,由于Spring Retry用到了Aspect增強(qiáng),所以就會(huì)有使用Aspect不可避免的坑——方法內(nèi)部調(diào)用,如果被 @Retryable 注解的方法的調(diào)用方和被調(diào)用方處于同一個(gè)類(lèi)中,那么重試將會(huì)失效。

但也還是存在一定的不足,Spring的重試機(jī)制只支持對(duì)異常進(jìn)行捕獲,而無(wú)法對(duì)返回值進(jìn)行校驗(yàn)。

到此這篇關(guān)于深入淺出Java中重試機(jī)制的多種方式的文章就介紹到這了,更多相關(guān)Java重試機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis實(shí)現(xiàn)一對(duì)一查詢映射處理

    Mybatis實(shí)現(xiàn)一對(duì)一查詢映射處理

    MyBatis是一種流行的Java持久化框架,它提供了靈活而強(qiáng)大的查詢映射功能,本文主要介紹了Mybatis實(shí)現(xiàn)一對(duì)一查詢映射處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • Java反射機(jī)制詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java反射機(jī)制詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java 反射機(jī)制。通俗來(lái)講呢,就是在運(yùn)行狀態(tài)中,我們可以根據(jù)“類(lèi)的部分已經(jīng)的信息”來(lái)還原“類(lèi)的全部的信息”。這篇文章給大家詳細(xì)介紹了java反射機(jī)制的知識(shí),感興趣的朋友一起看看吧
    2017-06-06
  • Spring?Data?Elasticsearch?5.0.x修改數(shù)據(jù)后無(wú)法立即刷新解決方法示例

    Spring?Data?Elasticsearch?5.0.x修改數(shù)據(jù)后無(wú)法立即刷新解決方法示例

    這篇文章主要為大家介紹了Spring?Data?Elasticsearch?5.0.x修改數(shù)據(jù)后無(wú)法立即刷新解決方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Java中十進(jìn)制和十六進(jìn)制的相互轉(zhuǎn)換方法

    Java中十進(jìn)制和十六進(jìn)制的相互轉(zhuǎn)換方法

    下面小編就為大家?guī)?lái)一篇Java中十進(jìn)制和十六進(jìn)制的相互轉(zhuǎn)換方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • 使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼

    使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼

    這篇文章主要介紹了使用Spring Data JDBC實(shí)現(xiàn)DDD聚合的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • Java集合Iterator迭代的實(shí)現(xiàn)方法

    Java集合Iterator迭代的實(shí)現(xiàn)方法

    這篇文章主要介紹了Java集合Iterator迭代接口的實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒家,對(duì)Java 結(jié)合iterator知識(shí)感興趣的朋友一起看看吧
    2016-08-08
  • Java 動(dòng)態(tài)編譯在項(xiàng)目中的實(shí)踐分享

    Java 動(dòng)態(tài)編譯在項(xiàng)目中的實(shí)踐分享

    在 Java 中,動(dòng)態(tài)編譯是指在運(yùn)行時(shí)動(dòng)態(tài)地編譯 Java 源代碼,生成字節(jié)碼,并加載到 JVM 中執(zhí)行,動(dòng)態(tài)編譯可以用于實(shí)現(xiàn)動(dòng)態(tài)代碼生成、動(dòng)態(tài)加載、插件化等功能,本文將給大家分享一下Java 動(dòng)態(tài)編譯在項(xiàng)目中的實(shí)踐,感興趣的同學(xué)跟著小編一起來(lái)看看吧
    2023-07-07
  • Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)

    Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)

    今天小編就為大家分享一篇關(guān)于Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)的文章,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • 學(xué)習(xí)Spring-Session+Redis實(shí)現(xiàn)session共享的方法

    學(xué)習(xí)Spring-Session+Redis實(shí)現(xiàn)session共享的方法

    本篇文章主要介紹了學(xué)習(xí)Spring-Session+Redis實(shí)現(xiàn)session共享的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • java實(shí)現(xiàn)響應(yīng)重定向發(fā)送post請(qǐng)求操作示例

    java實(shí)現(xiàn)響應(yīng)重定向發(fā)送post請(qǐng)求操作示例

    這篇文章主要介紹了java實(shí)現(xiàn)響應(yīng)重定向發(fā)送post請(qǐng)求操作,結(jié)合實(shí)例形式分析了java請(qǐng)求響應(yīng)、重定向及數(shù)據(jù)處理相關(guān)操作技巧,需要的朋友可以參考下
    2020-04-04

最新評(píng)論