Spring Boot 2에서 3으로 마이그레이션 하면서 작지만 중요한 변화 하나를 발견했다. 바로 요청 URL에 해당하는 핸들러(Controller)가 존재하지 않을 때의 예외 처리 방식이 변경된 것이다.
기존(Spring Boot 2.x ~ Spring Boot 3.1)의 동작 방식
Spring Boot 2.x 버전에서는 존재하지 않는 경로로 요청할 경우, @ControllerAdvice에 선언된 @ExceptionHandler(Exception.class)가 동작하지 않았다. 대신 Spring 자체의 오류 처리 페이지(resources/templates/error/4xx.html)가 렌더링 되었다.
변경 사항(Spring Boot 3.2부터)
Spring Boot 3.2부터는 NoHandlerFoundException도 @ControllerAdvice의 @ExceptionHandler로 전달되어 처리할 수 있게 되었다. (관련 이슈: https://github.com/spring-projects/spring-boot/issues/38733)
실습으로 비교해 보자
공통 설정
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
}
- /templates/index.html → 정상 페이지
- /templates/error/4xx.html → 오류 페이지
- '/' 요청을 처리하는 TestController
- Exception을 처리하는 GlobalExceptionHandler
// Controller
@Controller
public class TestController {
@GetMapping("/")
public String index() {
return "index";
}
}
// ExceptionHandler
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
System.out.println(e);
return "index";
}
}
1. Spring Boot 3.1.9에서의 동작
- '/' 요청 → index.html 정상 출력
- '/abcd' 요청 → 존재하지 않는 경로 → 4xx.html 렌더링 됨
→ GlobalExceptionHandler는 호출되지 않음
즉, Spring 내부 오류 처리로 빠진다.
2. Spring Boot 3.2.5에서의 동작
- /abc 요청 시 → GlobalExceptionHandler가 호출됨
- 디버깅 결과: NoResourceFoundException 발생
- 결과적으로 index.html이 렌더링 됨
즉, 이제는 존재하지 않는 경로도 개발자가 정의한 글로벌 핸들러에서 처리할 수 있게 되었다.
정리 및 주의사항
- Spring Boot 3.2부터는 NoHandlerFoundException (또는 내부적으로 던지는 NoResourceFoundException)도 @ControllerAdvice로 처리 가능하다.
- 기존에는 4xx.html, 5xx.html 등으로 구분해 템플릿 렌더링했지만, 이제는 글로벌 예외 처리에 걸리기 때문에 기대했던 템플릿이 아닌 다른 뷰가 렌더링 될 수 있다.
- 따라서 마이그레이션 시, @ControllerAdvice의 ExceptionHandler가 모든 예외를 catch 하고 있는지 확인하고, 특정 예외만 처리하도록 조건을 걸어두는 것이 좋다.
'Spring' 카테고리의 다른 글
@Transactonal (1) | 2023.05.11 |
---|---|
Maven (0) | 2021.06.19 |