기존의 비대했던 ErrorResponseGlobalExceptionHandler전략 패턴(Strategy Pattern)으로 개편하여 유지보수성, 가독성, 확장성을 극대화한 구조입니다.


1. 시스템 핵심 구조도

이 시스템은 예외가 발생하면 ErrorDispatcher가 등록된 모든 전략 중 적절한 것을 찾아 처리하고, 일관된 ErrorResponse를 반환하는 구조입니다.


2. 인터페이스와 추상화: ExceptionStrategy

모든 예외 처리 로직의 규격입니다. 각 예외별로 "내가 처리할 수 있는가?"(isSupport)와 "어떤 에러 코드/상세를 반환할 것인가?"를 정의합니다.

public interface ExceptionStrategy<T extends Exception> {
    boolean isSupport(Exception e); // 처리 가능 여부 확인
    ErrorCode getErrorCode(T e);    // 에러 코드 매핑
    default Map<String, Object> getDetails(T e) { // 상세 정보 (선택적)
        return Collections.emptyMap();
    }
}

3. 대표적인 전략 구현체 소개

수많은 예외 타입을 단 3가지 유형의 핵심 전략으로 대표하여 관리할 수 있습니다.

3.1. CustomExceptionStrategy (비즈니스 예외)

개발자가 의도적으로 던지는 모든 비즈니스 예외를 처리합니다. 예외 객체 내부에 포함된 ErrorCode와 커스텀 details를 그대로 추출합니다.

@Component
public class CustomExceptionStrategy implements ExceptionStrategy<CustomException> {
    @Override 
    public boolean isSupport(Exception e) { return e instanceof CustomException; }
    
    @Override 
    public ErrorCode getErrorCode(CustomException e) { return e.getErrorCode(); }
    
    @Override 
    public Map<String, Object> getDetails(CustomException e) { return e.getDetails(); }
}

3.2. AuthenticationStrategy (보안 인증 예외)

Spring Security 인증 과정에서 발생하는 복잡한 예외 계층을 분석합니다. BadCredentialsException, LockedException 등을 각각의 ErrorCode로 정밀하게 매핑합니다.

@Component
public class AuthenticationStrategy implements ExceptionStrategy<AuthenticationException> {
    @Override 
    public boolean isSupport(Exception e) { return e instanceof AuthenticationException; }
    
    @Override 
    public ErrorCode getErrorCode(AuthenticationException e) {
        // 내부 원인 예외가 있다면 이를 추출하여 정확한 에러 코드 반환
        Throwable target = (e.getCause() instanceof AuthenticationException ae) ? ae : e;
        
        if (target instanceof UsernameNotFoundException) return ErrorCode.USER_NOT_FOUND;
        if (target instanceof BadCredentialsException) return ErrorCode.INVALID_USER_CREDENTIALS;
        if (target instanceof LockedException) return ErrorCode.ACCOUNT_LOCKED;
        
        return ErrorCode.INVALID_TOKEN; // 기본 보안 에러
    }
}