Resiliency4j CircuitBreaker试图在AOP中调用CircuitBreaker逻辑,以实现在配置中



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

我尝试使用下面的演示示例来扩展到我的需求,我尝试在application.propertytruefalse的情况下,基于断路器标志spring.cloud.circuitbreaker.resilience4j.enabled=true将断路器调用绑定到目标方法上。有一种更简单的方法可以实现这一点,如果有其他解决方案,请帮助我。

示例:弹簧云断路器-弹性4j示例

尝试调用快乐路径-当没有异常时工作正常[响应在3秒内出现,因为在bean创建中时间限制设置为3秒]

应用程序。属性:

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

控制器:

@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());
}
}

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

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

AOP:CircuitBreakerAround方面:

@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;
}
}

我的要求:circuitBreakerFactory.create(joinPoint.getSignature().toString()) .run(() -> ....)在这一行,当目标方法抛出异常时,controll应该转到回退机制调用。由于joinPoint.proceed((抛出异常,它强制处理异常-所以我在这里做得不对,需要建议来解决这个问题以解决需求。

错误日志:

{
"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')rntat com.ravibeli.circuitbreaker.service.MockService$$EnhancerBySpringCGLIB$$3e293bd0.delay(<generated>)rntat com.ravibeli.circuitbreaker.controllers.DemoController.delay(DemoController.java:53)rntat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)rntat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)rntat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)rntat java.base/java.lang.reflect.Method.invoke(Method.java:566)rntat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)rntat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)rntat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)rntat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)rntat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)rntat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)rntat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063)rntat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)rntat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)rntat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)rntat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)rntat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)rntat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:228)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)rntat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)rntat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)rntat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)rntat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)rntat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)rntat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)rntat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)rntat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)rntat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)rntat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)rntat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)rntat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)rntat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)rntat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)rntat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)rntat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)rntat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)rntat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1723)rntat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)rntat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)rntat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)rntat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)rntat java.base/java.lang.Thread.run(Thread.java:834)rn",
"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"
}

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

标题似乎在问,当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. 就您方面的代码而言,它看起来和运行对我来说都很好。链接到代码。如果您可以共享到代码库的链接,以便对该问题进行进一步调查,那将是更好的选择。不过,这似乎是个小问题

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

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

最新更新