나만보는페이지

[Spring MVC] RequestMapping 핸들러 초기화 과정 본문

spring

[Spring MVC] RequestMapping 핸들러 초기화 과정

pplenty 2020. 4. 1. 23:51

boot-2.1.3(spring 5.1.5) 기준으로 작성하였다.

스프링에서 컨트롤러 메서드가 URL 에 매핑 되는 과정을 살펴본다. 개인적으로 스프링은 naming 이 정말 쉽게 잘 되어 있다고 생각한다.
RequestMapping 과 관련된 빈의 이름은 requestMappingHandlerMapping 이다.
빈 이름으로만 어떤 역할을 하는지 추정해보면 RequestMapping 과 Handler 를 매핑해 주는 빈이라고 유추가 가능하다.
빈 초기화는 ApplicationContext refresh 과정(11) 중에 일어난다.
@Bean으로 설정 되어있는 RequestMappingHandlerMapping 빈의 생성 후 초기화(InitializingBean) 하는 과정을 자세하게 살펴보자!

클래스 구조

클래스다이어그램

핸들러 매핑(RequestMappingHandlerMapping bean initialize) 전체 흐름

  1. RequestMappingHandlerMapping 빈 생성
  2. 빈 초기화 하면서, initHandlerMethods 호출
  3. 빈 팩토리에 등록되어 있는 빈들 중 @Controller 또는 @RequestMapping 를 가지고 있는 빈을 가져온다.
  4. 핸들러가 될 수 있는 모든 메서드를 추출한다.(detectHandlerMethods)
  5. 추출된 메서드를 registry 에 등록한다.(registerHandlerMethod)

주요 함수

(1) requestMappingHandlerMapping()

  • 빈을 생성하는 팩토리 메서드이다. RequestMappingHandlerMapping 의 생성자릍 통해 호출한 뒤, order 와 설정 정보들을 세팅한다.
    Interceptor 가 추가되는 부분이기도 하다.
    빈생성

(2) processCandidateBean()

  • 후보 빈 이름으로 타입 정보를 가져온다.
    후보빈
  • 타입 정보를 분석하여 Annotation 으로 핸들러 여부를 파악한다. RequestMappingHandlerMapping 에서는 @Controller@RequestMapping 로 판별하도록 구현되어 있다.
    물론 @GetMapping 이나 @RestController 와 같은 어노테이션도 해당된다.
    핸들러인지

(3) detectHandlerMethods(Object handler)

  • Handler 빈 또는 빈 이름을 인자로 전달 받을 수 있다. 즉, ApplicationContext(빈 팩토리) 에서 Controller 의 빈 이름으로 빈의 타입을 가져온다.
    빈의 Class 정보에서 reflect api 로 메서드(핸들러) 정보를 조회하여, 각 메서드의 어노테이션을 분석해 리퀘스트매핑 정보를 생성한다.
    핸들러메서드추출

(4) getMappingForMethod(Method method, Class<?> handlerType)

  • 컨트롤러와 핸들러의 리퀘스트매핑 정보(RequestMappingInfo 객체)를 생성하는 함수이다.
    method(handler) 에서 RequestMapping annotation 의 정보를 기반으로 RequestMappingInfo 를 만든다.
    handlerType(Controller) 에도 정보가 있다면 동일한 과정을 거치고, 두 정보를 조합한다.
    매핑정보만들기

(5) createRequestMappingInfo(AnnotatedElement element)

  • 빌더 패턴을 이용하여 RequestMappingInfo 를 생성하는 함수이다. @RequestMapping 어노테이션에 설정할 수 있는 정보들을 기반으로 객체를 생성한다.
    매핑정보빌더

(6) register(T mapping, Object handler, Method method)

  • 앞의 과정에서 생성한 메서드 정보(HandlerMethod)들을 MappingRegistry 에 등록한다. 이곳에 등록된 정보들은 DispatcherServlet 에서 요청에 매핑되는 Handler 를 조회할 때 이용된다.
    RequestMappingHandlerMapping 에서 T mapping 타입은 RequestMappingInfo 로 결정된다.
    핸들러등록
  • MultiValueMap<String, T> urlLookup 에는 URL 을 키로 매핑 정보를 등록하고, Map<T, HandlerMethod> mappingLookup 에는 매핑 정보를 키로 핸들러를 등록한다.
    매핑레지스트리

정리

대부분의 함수가 상위 class 인 AbstractHandlerMethodMapping 의 함수이고 몇몇 abstract 함수만이 RequestMappingHandlerMapping 에서 구현되어 있다. RequestMapping 핸들러 판별 함수(isHandler) , 등록할 매핑 정보를 만드는 함수(getMappingForMethod) 등이 구현체에서 구현된 함수이다.
이렇게 정리하고 보니 새삼 스프링의 확장성이 대단하다고 느낀다. 구현체를 만들어 몇몇 함수만 구현해서 빈으로 등록하여 Custom 한 매핑정보를 만들어 핸들러와 매핑시킬 수 있으니 말이다.

Comments