IT IT 인터넷 spring mvc openFeign@ControllerAdvice

http://java21.net/blog/marco?post_id=2423

OpenFeign 공통 예외처리

Feign 클라이언트에서 발생하는 예외를 공통적으로 처리하는 방법을 소개하겠습니다. Spring에서 제공하는 예외 처리 메커니즘을 활용하여 Feign의 예외를 공통적으로 처리할 수 있습니다. 이를 통해 여러 서비스에서 발생할 수 있는 예외를 중앙에서 처리하고, 중복 코드를 방지할 수 있습니다.

1. @ControllerAdvice를 이용한 공통 예외 처리

Spring에서 @ControllerAdvice를 사용하여 전역적으로 예외를 처리할 수 있습니다. Feign 클라이언트에서 발생한 예외도 이를 통해 처리할 수 있습니다. Feign은 FeignException을 던지므로 이를 처리하는 방법을 소개합니다.

예외 처리 클래스 정의

@ControllerAdvice를 사용하여 Feign 예외를 처리하는 클래스는 다음과 같습니다.

import feign.FeignException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(FeignException.class)
    public ResponseEntity<String> handleFeignException(FeignException ex) {
        // FeignException이 발생한 경우 공통적으로 처리
        HttpStatus status = HttpStatus.valueOf(ex.status());
        String errorMessage = "Feign 클라이언트 호출 중 오류 발생: " + ex.getMessage();
        
        // 필요에 따라 로깅 추가
        // 로그 예시: logger.error("Feign 호출 오류: ", ex);

        return new ResponseEntity<>(errorMessage, status);
    }

    // 다른 공통 예외 처리도 추가할 수 있습니다.
}

  • @RestControllerAdvice: 이 어노테이션은 예외를 처리하는 컨트롤러에서 발생하는 예외를 처리합니다.

  • @ExceptionHandler(FeignException.class): FeignException을 처리하는 메서드를 지정합니다. FeignException은 Feign 클라이언트에서 발생할 수 있는 예외의 최상위 클래스입니다.

  • ResponseEntity: 클라이언트에 반환할 HTTP 상태 코드와 메시지를 설정합니다.

2. FeignException 종류

FeignException은 여러 종류가 있을 수 있습니다. 상태 코드에 따라 다른 처리 로직을 구현하고 싶다면, status() 메서드를 통해 HTTP 상태 코드를 확인하고 해당 코드를 기반으로 분기할 수 있습니다.

예를 들어, HTTP 404(Not Found)와 500(Internal Server Error) 상태 코드를 구분하여 처리할 수 있습니다.

@ExceptionHandler(FeignException.class)
public ResponseEntity<String> handleFeignException(FeignException ex) {
    HttpStatus status = HttpStatus.valueOf(ex.status());
    String errorMessage;
    
    if (status == HttpStatus.NOT_FOUND) {
        errorMessage = "요청한 리소스를 찾을 수 없습니다. (404 오류)";
    } else if (status == HttpStatus.INTERNAL_SERVER_ERROR) {
        errorMessage = "서버 내부 오류가 발생했습니다. (500 오류)";
    } else {
        errorMessage = "Feign 클라이언트 호출 중 오류 발생: " + ex.getMessage();
    }
    
    return new ResponseEntity<>(errorMessage, status);
}

3. Fallback을 사용한 예외 처리

Feign의 fallback 기능을 활용하여 클라이언트가 호출하는 외부 서비스에서 오류가 발생할 경우 대체 응답을 제공할 수 있습니다. 이를 통해 애플리케이션의 안정성을 높일 수 있습니다.

@FeignClient(name = "example-client", url = "https://api.example.com", fallback = ExampleClientFallback.class)
public interface ExampleClient {

    @GetMapping("/data")
    String getData();
}

ExampleClientFallback 클래스는 Feign 클라이언트 호출이 실패할 경우 대체 응답을 제공하는 클래스입니다.

import org.springframework.stereotype.Component;

@Component
public class ExampleClientFallback implements ExampleClient {

    @Override
    public String getData() {
        return "Fallback response: 외부 API 호출에 실패했습니다.";
    }
}

4. 예외 처리와 로깅

Feign 예외 처리 시, 로그를 기록하여 디버깅에 도움이 되도록 할 수 있습니다. 예외를 처리하는 GlobalExceptionHandler 클래스에서 예외를 로깅하면, 어떤 요청에서 오류가 발생했는지 추적할 수 있습니다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(FeignException.class)
    public ResponseEntity<String> handleFeignException(FeignException ex) {
        HttpStatus status = HttpStatus.valueOf(ex.status());
        String errorMessage = "Feign 클라이언트 호출 중 오류 발생: " + ex.getMessage();

        // 예외 로깅
        logger.error("Feign 호출 오류: 상태 코드 = {}, 메시지 = {}", ex.status(), ex.getMessage());

        return new ResponseEntity<>(errorMessage, status);
    }
}

5. 결론

Feign에서 발생하는 예외를 공통적으로 처리하는 방법은 @ControllerAdvice@ExceptionHandler를 활용하여 중앙에서 처리하는 것입니다. 이를 통해 코드의 중복을 줄이고, 예외 처리 로직을 한 곳에서 관리할 수 있습니다. 또한, fallback을 사용하여 서비스가 실패할 경우 대체 응답을 제공하고, Feign 클라이언트에서 발생하는 오류를 로깅하여 디버깅에 도움이 되도록 할 수 있습니다.

이와 같은 예외 처리 방법을 사용하면 안정적이고 일관된 방식으로 서비스 간의 통신 오류를 처리할 수 있습니다.