首页 > 解决方案 > 使用 @ControllerAdvice 和 @CircuitBreaker 的 Spring Boot 微服务异常行为

问题描述

我的问题与微服务中的异常行为有关。假设我们有一个微服务(比如说微服务-A),它有一个控制器建议注释类来处理所有异常。

此外,我的微服务-A 正在调用另一个微服务(比如说微服务-B)。假设此调用是从带有注释的服务层方法发生的@CircuitBreaker(name="myService", fallback="myFallbackMethod")

那么如果我在成功调用微服务-B之后引入了任何运行时异常,是会执行回退方法,还是会执行被注释类@ExceptionHandler中存在的被注释方法@ControllerAdvice

连接 poc

    //Microservice-A
    package com.example.iplservice.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.core.env.Environment;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import com.example.iplservice.feign.MyFeignClient;
    import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
    
    @RestController
    
    @RequestMapping("ipl")
    
    public class IplController {
    
        @Value("${ipl.team}")
        private String iplTeam;
    
        @Autowired
        private Environment env;
    
        @Autowired
        private MyFeignClient myFeignClient;
    
        @GetMapping("/team/hello")
        @CircuitBreaker(name = "cricketService", fallbackMethod = "getHelloFallBack")
        public ResponseEntity < String > getHello() {
            String body = myFeignClient.getHello().getBody();
            //introducing an error here!!
            int a = 2 / 0;
            System.out.println("-----------------" + a);
            return ResponseEntity.ok("Hello " + iplTeam + " : " + env.getProperty("local.server.port") + " : Called : " + body);
        }
    }
    //Microservice-A ends
    //Microservice-A Controller Advice
    package com.example.iplservice.excetion;
    
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
    
    @ControllerAdvice
    public class CricketExceptionHandler extends ResponseEntityExceptionHandler {
    
        @ExceptionHandler(Exception.class)
        public ResponseEntity < String > handleGenericException(Exception ex) {
            return ResponseEntity.ok("Error From Controller Advice : " + ex.getMessage());
        }
    }
    //Microservice-A Controller Advice ends
    //Microservice-B
    package com.example.cricketersdetailservice.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.core.env.Environment;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RefreshScope
    @RequestMapping("/cricket")
    public class CricketController {
    
        @Value("${cricketer.team}")
        private String teamName;
    
        @Autowired
        private Environment env;
    
        @GetMapping("/team/hello")
        public ResponseEntity < String > getHello() {
            return ResponseEntity.ok("Hello " + teamName + " : " + env.getProperty("local.server.port"));
        }
    }
    //Microservice-B ends

标签: javaspringspring-bootmicroservices

解决方案


正如我在代码中看到的,将触发回退方法。即使对微服务 B 的调用成功,Circuit Breaker 也会监视方法上发生的每个异常getHello

如果你想改变这种行为,有一些选择:

  • 仅使用断路器装饰 feign 客户端方法调用
  • 将 feign 客户端调用分离到一个新方法上,并用@CircuitBreaker
  • 配置熔断器以仅监视 feign 客户端抛出的某些特定异常

在此处此处查看弹性 4j 文档


推荐阅读