Spring Boot는 기본으로 MessageSource를 통한 메시지 기능과 Validation 기능을 제공한다. 그런데 MessageSource가 어떻게 동작하는지, 왜 RequestBody는 @Valid 어노테이션 만으로 유효성 검증이 되고 RequestParam은 조건부로 검증이 되며 Type level에 @Validated가 붙어야 하는지 궁금했다. 그래서 한번 내부 구현을 들여다보았다.
내부 구현 정리와 근거
ApplicationContext는 MessageSource를 구현
MessageSource는 Bean으로 등록된 것으로 설정
MessageSource는 MessageSourceAutoConfiguration에서 bean으로 생성
ValidationAutoConfiguration에서 defaultValidator bean 생성
defaultValidator는 applicationContext bean을 등록
validator bean의 messageInterplator 적용부에 applicationContext가 들어감
MethodValidationPostProcessor는 ObjectProvider 통해 validator bean을 찾아 주입
→ Validator, MethodValidationPostProcessor는 동일한 validator를 사용
WebMvcAutoConfiguration에서 mvcValidator를 등록
jakarta.validation.Validator 내부에 있는 validator를 가져오는 역할
mvcValidator는 defaultValidator와 같음
@RequestMapping은 requestMappingHandlerAdapter bean을 통해 처리
Spring은 RequestMapping을 통해 받은 파라미터를 argumentResolver를 통해 처리
@RequestBody는 RequestResponseBodyMethodProcessor를 통해 처리
RequestResponseBodyMethodProcessor는 @Valid가 붙은 validation을 처리
Pageable 파라미터는 PageableHandlerMethodArgument에서 처리
validation 되지 않음
그 외 요청의 경우 각각 필요한 argumentResolver를 통해 처리
argumentResolver에서 validation을 처리해주지 않는 경우 클래스 단에 @Validated 어노테이션을 붙여 MethodValidationPostProcessor를 통해 처리 되도록 해야함
상기 내용과 같이 Method에 Validation Annotation처리가 되어있는 제약조건을 처리하기 위해 Type Level(클래스 단)에 붙어야함
→ PageableHandlerMethodArgumentResolver에서 validation을 해주지 않기 때문에 Validated를 통해 MethodValidationPostProcessor에서 동작하도록 설정
→ MethodValidationPostProcessor에 등록된 메서드는 MethodValidationInterceptor를 통해 validation 처리
→ requestMappingHandlerAdapter를 통해 처리되는 RequestMapping 메서드를 MethodValidationInterceptor가 가로채어 validation됨
MethodValidationPostProcessor에 확인된 클래스 메서드는 실행 시 MethodValidationInterceptor를 통해 처리 중간에 가로채어 validation 됨
RequestBody외 다른 파라미터는 클래스 단에 @Validated를 명시하여 MethodValidationInterceptor를 통해 가로채어 처리 해야함