Java @使用@CircuitBreaker时,一旦使用了所有重试,则不会调用Recover(回退方法)

Java @使用@CircuitBreaker时,一旦使用了所有重试,则不会调用Recover(回退方法),java,rest,spring-boot,microservices,spring-retry,Java,Rest,Spring Boot,Microservices,Spring Retry,尽管对于其他返回类型,Spring重试回退机制似乎工作得很好,但在调用返回类型为void的API时。恢复方法根本没有被调用,我尝试了所有可能的方法参数类型,并更改了回退方法的返回类型。。。。有办法吗?我不明白为什么@CircuitBReaker注释没有一个参数来接受作为值传递给它的回退方法名称 @CircuitBreaker(maxAttempts = 3, openTimeout = 8000, resetTimeout = 15000) public Void calling

尽管对于其他返回类型,Spring重试回退机制似乎工作得很好,但在调用返回类型为void的API时。恢复方法根本没有被调用,我尝试了所有可能的方法参数类型,并更改了回退方法的返回类型。。。。有办法吗?我不明白为什么@CircuitBReaker注释没有一个参数来接受作为值传递给它的回退方法名称

    @CircuitBreaker(maxAttempts = 3, openTimeout = 8000, resetTimeout = 15000)
    public Void callingXYZ(final Abc abc, final Cdf cdf) {
        return retryTemplate.execute(context -> {
            log.info("Retry count={} when calling ******", context.getRetryCount());
            AbcServiceImpl.this.update*****Settings(OrgId.fromString(abc.getUUID(), cdf.getData());
            return null;
        });
    }

   //Recover method that should get invoked
    @Recover
    public Void fallbackUpdate*****(Throwable e, Abc abc) throws Throwable{
        log.info("Inside fallback");
        if (e instanceof ClientException) {
            log.warn("Fallback method is called when trying to call ******** from ****** because of {}", e.getCause());

   //Rollback in the db based on the method attributes
            throw SpecificException.forTask(HttpStatus.SERVICE_UNAVAILABLE.value(),
                    Enum.NAME.getErrorCode(),
                    Enum.NAME.getMEssage(), true);
        }
        throw e;
    } 


试着使用@Retryable,它对我很有用

 <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.5.RELEASE</version>
    </dependency>

@Retryable(value = { NullPointerException.class},maxAttempts = 2)
public void retry() throws NullPointerException{
    throw new NullPointerException("something went wrong");
}

@Recover
public void recover(NullPointerException ex)
{
    System.out.println("iniside recover");
}

org.springframework.retry

我在代码中解决了这个问题,它与spring重试项目无关。我无法找到问题的解决方案,因为我对AOP的Spring实现缺乏理解。由于Spring的方面应用于围绕bean的代理,而不是实际的类,因此如果从同一个类/服务调用带有@circuitbreaker的方法,则调用该方法将不起作用。

您是否曾经用@Transactional(或例如@Async)注释过一个方法,但它不起作用?好像它被春天完全忽略了?这是因为这样的注释不能(至少在默认情况下)仅放在任何方法上,必须满足以下两个条件才能让Spring执行操作:

方法可见性只能是public。 调用必须来自bean的外部。 这是由于Spring代理在默认情况下的工作方式(使用CGLIB代理)。我不会深入讨论细节,因为这是一个足够广泛的主题,可以写另一篇文章,但一般来说,当您自动连接Sample类型的bean时,Spring实际上并没有为您提供Sample的实例。相反,它注入了一个生成的代理类,该类扩展了Sample(这就是为什么不能将springbean类设置为final),并重写了它的公共方法,以便能够添加额外的行为(比如事务支持)

这就是为什么带有@Transactional的方法必须是公共的(因此Spring可以轻松地重写它们),也就是为什么调用必须来自外部(只有这样它才能通过代理,Spring才能用代理引用替换此引用)


摘自

,但它不允许我使用断路器模式…我希望在上次重试和重置之间有一个间隙,以便让相应的服务调用恢复。我希望同时使用重试和断路器。如果有人面临相同的问题,但仍在解决方案中遇到困难,请在此处发表评论,我将尝试用简短的文字解释代码示例。在排序中,如果您正在使用内置Spring的AOP,那么如果您不将所有断路器方法移动到新的或不同的服务中,您可以使其工作。