🛠️ [트러블슈팅] 공통 GlobalExceptionHandler가 작동하지 않는 이슈 해결기
2025. 5. 21. 17:03

📌 문제 상황

Spring Cloud 기반 MSA 프로젝트에서 예외 처리 통일을 위해
common-library 모듈에 GlobalExceptionHandler를 정의했지만,
user-service, order-service 등 개별 서비스에서는
예외가 발생해도 해당 핸들러가 작동하지 않고 기본 Spring 오류 포맷으로 응답되는 문제가 있었습니다.

공통 라이브러리에서 정의한 핸들러가 정상 작동하지 않는 현상

🧠 원인 분석

1️⃣ @RestControllerAdvice는 Spring의 컴포넌트 스캔 대상이어야만 빈으로 등록됩니다.
그러나 common-library는 외부 모듈(jar)이기 때문에,
서비스의 @SpringBootApplication 기본 스캔 범위 밖에 있어 자동 등록되지 않았습니다.

2️⃣ 서비스 내에서 별도로 정의된 UserNotFoundException 등과 공통 모듈의 예외 클래스가 중복되면,
예외 매핑이 일어나지 않아 핸들러가 무시됩니다.


🔨 해결 과정

✅ 1. 공통 라이브러리에서 핸들러 정의

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ApiResponse<Object>> handleUserNotFound(UserNotFoundException e) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(ApiResponse.fail(e.getMessage()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Object>> handleGeneral(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(ApiResponse.fail("서버 내부 오류가 발생했습니다."));
    }
}

✅ 2. 각 서비스에서 명시적으로 등록

방법: @Import(GlobalExceptionHandler.class) 사용

@SpringBootApplication
@Import(GlobalExceptionHandler.class)
public class UserServiceApplication { ... }

✅ 3. 중복 예외 클래스 제거 및 통일

서비스 내에 정의되어 있던 UserNotFoundException을 제거하고,
common-library에 정의된 클래스를 단일 소스로 사용하도록 정리했습니다.


📈 결과 & 정리

항목 개선 전 개선 후
예외 응답 Spring 기본 오류 형식 공통 ApiResponse.fail(...) 포맷
메시지 일관성 없음 서비스 전체 통일된 메시지
핸들러 재사용성 서비스마다 중복 정의 공통 라이브러리로 통합
유지보수성 낮음 변경 시 단일 위치에서 관리 가능

💡 배운 점

  • 공통 모듈에 선언된 @RestControllerAdvice는 자동 등록되지 않는다 → @Import나 @ComponentScan 필요
  • 예외 클래스는 중복 정의되면 매핑이 깨질 수 있으므로 반드시 통합 관리
  • MSA 환경에서 예외 처리 흐름은 초기에 구조로 설계해두는 것이 중요
  • 커스텀 어노테이션을 활용하면 반복 설정 없이 쉽게 확장 가능

📚 추가 자료