微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Resiliency4j CircuitBreaker 尝试在 AOP 中调用 CircuitBreaker 逻辑,以实现在 config

如何解决Resiliency4j CircuitBreaker 尝试在 AOP 中调用 CircuitBreaker 逻辑,以实现在 config

有条件地,我想通过设置 spring.cloud.circuitbreaker.resilience4j.enabled=false关闭/打开断路器开关。我的逻辑应该与断路器逻辑保持一致。

我尝试使用下面的演示示例来扩展我的要求,我正在尝试根据 spring.cloud.circuitbreaker.resilience4j.enabled=trueapplication.propertytrue 中的断路器标志 false 绑定目标方法上的断路器调用spring.cloud.circuitbreaker.resilience4j.enabled=true spring.cloud.config.enabled=false spring.cloud.config.import-check.enabled=false spring.main.allow-bean-deFinition-overriding=true 情况。可能有一种更简单的方法来实现这一点,如果有任何其他解决方案而不是我尝试过的方法,请帮助我。

示例: spring cloud circuit-breaker-resiliency4j example

尝试调用happy path - 在没有异常的情况下工作正常[响应在3秒内出现,因为时间限制器在bean创建中设置为3秒]

application.properties:

@GetMapping("/delay/{seconds}")
public Map delay(@PathVariable int seconds) {
   return mockService.delay(seconds);
}

控制器:

@ApplyCircuitBreaker
public Map delay(int seconds) {
    return rest.getForObject("https://httpbin.org/delay/" + seconds,Map.class);
}

模拟服务:

@Configuration
@ConditionalOnProperty(name = { "spring.cloud.circuitbreaker.resilience4j.enabled"},matchIfMissing = true)
public class ResiliencyConfig {

    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
            .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(3)).build())
            .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
            .build());
    }
}

配置类:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApplyCircuitBreaker {
}

ApplyCircuitBreaker - 自定义注释以仅对所需方法应用断路器:

@Aspect
@Component
@ConditionalOnProperty(name = { "spring.cloud.circuitbreaker.resilience4j.enabled","spring.cloud.circuitbreaker.resilience4j.reactive.enabled" },matchIfMissing = true)
public class CircuitBreakerAroundAspect {

    @Autowired
    CircuitBreakerFactory circuitBreakerFactory;

    @Around("@annotation(com.ravibeli.circuitbreaker.aspects.ApplyCircuitBreaker)")
    public Object aroundAdvice(final ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Arguments passed to method are: {}",Arrays.toString(joinPoint.getArgs()));
        atomicreference<Map<String,String>> fallback = new atomicreference<>();
        Object proceed = circuitBreakerFactory.create(joinPoint.getSignature().toString())
            .run(() -> {
                try {
                    log.info("Inside CircuitBreaker logic in Aspect");
                    return joinPoint.proceed();
                } catch (Throwable t) {
                    log.error(t.getMessage());
                }
                return null;
            },Throwable::getMessage);
        log.info("Result from method is: {}",proceed);
        return proceed;
    }
}

AOP:CircuitBreakerAroundAspect:

circuitBreakerFactory.create(joinPoint.getSignature().toString()) .run(() -> ....)

我的要求: { "timestamp": "2021-07-10T01:33:10.558+00:00","status": 500,"error": "Internal Server Error","trace": "java.lang.classCastException: class java.lang.String cannot be cast to class java.util.Map (java.lang.String and java.util.Map are in module java.base of loader 'bootstrap')\r\n\tat com.ravibeli.circuitbreaker.service.MockService$$EnhancerBySpringcglib$$3e293bd0.delay(<generated>)\r\n\tat com.ravibeli.circuitbreaker.controllers.DemoController.delay(DemoController.java:53)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.invocableHandlerMethod.doInvoke(invocableHandlerMethod.java:197)\r\n\tat org.springframework.web.method.support.invocableHandlerMethod.invokeForRequest(invocableHandlerMethod.java:141)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletinvocableHandlerMethod.invokeAndHandle(ServletinvocableHandlerMethod.java:106)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.dispatcherServlet.dodispatch(dispatcherServlet.java:1063)\r\n\tat org.springframework.web.servlet.dispatcherServlet.doService(dispatcherServlet.java:963)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:228)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1723)\r\n\tat org.apache.tomcat.util.net.socketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\n","message": "class java.lang.String cannot be cast to class java.util.Map (java.lang.String and java.util.Map are in module java.base of loader 'bootstrap')","path": "/delay/3" } 在这一行,当目标方法抛出异常时,控制应该去回退机制调用。由于 joinPoint.proceed() 抛出异常,它强制处理异常 - 所以我在这里做错了,需要建议来解决这个问题以解决需求。

错误日志:

liblib.so

解决方法

您似乎在这里问了几个不同的问题。

标题似乎在问为什么当方面仍然存在时 spring.cloud.circuitbreaker.resilience4j.enabled=false

问题在于你的条件

@ConditionalOnProperty(name = { "spring.cloud.circuitbreaker.resilience4j.enabled","spring.cloud.circuitbreaker.resilience4j.reactive.enabled" },matchIfMissing = true)

它只是要求属性存在,而不是检查它的设置。您还需要设置 havingValue=true

也就是说,我强烈建议不要为断路器制作自己的切入点。使用 Resiliancy4j 提供的注释并在那里指定回退方法。我希望这可以解决您在回退方面遇到的任何其他问题。

@Bulkhead(name = 'myService',fallbackMethod = "myFallback")
@CircuitBreaker(name = 'myService',fallbackMethod = "myFallback")
@RateLimiter(name = 'myService',fallbackMethod = "myFallback")
@TimeLimiter(name = 'myService',fallbackMethod = "myFallback")
,
  1. 要动态启用断路器,您可以使用配置文件或外部化配置(首选方法是使用配置文件,您可以在谷歌上搜索更多相关信息)
  2. 就您的方面的代码而言,它对我来说看起来和运行都很好。 Link to Code。如果您可以共享代码库的链接,以便可以进一步调查该问题,那就更好了。不过,这似乎是一个小问题。
,

谢谢大家的评论,有了解决这个问题的简单想法。 我使用自定义工厂实现解决了该问题,以使启用/禁用功能正常工作。

我的 GitHub 示例代码: spring-cloud-resiliency4j

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。