SimpleUrlHandlerMapping 실제 코드 살펴보기

구동희·2022년 10월 23일
0

HandlerMapping

HandlerMappingSpring에서 어떤 역할을 하는지에 대해서 이전 포스팅에서 다뤄 보았다.
그래서 이번 포스팅에서는 이 부분에 대해서 건너뛰고 SimpleUrlHandlerMapping에 대해서 살펴보자.

HandlerMapping과 BeanNameUrlHandlerMapping 살펴보기

SimpleUrlHandlerMapping

SimpleUrlHandlerMapping은 빈 인스턴스와 URL 또는 빈 이름과 URL 간의 직접적이고 선언적인 매핑을 통해 Handler들을 등록하는 HandlerMapping이다.

코드를 통해 위 설명을 살펴보자.

우선, 위와 같이 SimpleUrlHandlerMapping을 빈 등록해준다. 그리고 Map<String, Object>url을 key, handler를 value로 값을 넣어준다.

그리고 18번 줄과 같이 simpleUrlHandlerMapping.setUrlMap()을 호출해주면 SimpleUrlHandlerMappingWelcomeControllerHandler로 등록될 것이다.

테스트 코드 디버그를 통해 SimpleUrlHandlerMappingHandler가 잘 등록되었는지 살펴보자.

위 코드는 SimplerHandlerMapping이 필드인 HandlerMap에 예상한 Handler를 가지고 있는지 확인하기 위한 테스트 코드이다.

디버그를 통해 확인해보면SimpleUrlHandlerMappinghandlerMapkeyvalue가 각각 "/simpleUrlWelcome", WelcomeController로 예상과 같이 설정 되었음을 알 수 있다.

이제 다시 SimpleUrlHandlerMapping에 대한 처음 설명을 보면 쉽게 이해가 된다.

SimpleUrlHandlerMapping은 빈 인스턴스와 URL 또는 빈 이름과 URL 간의 직접적이고 선언적인 매핑을 통해 Handler들을 등록하는 HandlerMapping이다.

SimpleUrlHandlerMapping은 빈 인스턴스와 URL을 직접적이고 선언적인 매핑을 한다고 말한다.
처음의 @Configuration 코드를 다시보자.

위 코드를 보면 개발자가 WelcomeController라는 Handler"/simpleUrlWelcome" 이라는 url을 직접적이고 선언적으로 코드에 나타내었음을 볼 수 있다.

그래서 SimpleUrlHandlerMapping가장 유연한 HandlerMapping이라고도 한다.
개발자가 직접적으로 설정하는 부분이 가장 많기 때문이다.

SimpleUrlHandlerMapping 특징

SimpleUrlHandlerMapping은 직접적이고 선언적인 HandlerMapping인 만큼 한가지 특징을 가진다.
바로, 한가지 Handler에 여러가지 url을 매핑하기 쉽다는 것이다.

코드를 통해 살펴보자.

위 코드를 보면 WelcomeController에 3가지의 url을 매핑했음을 알 수 있다.
마찬가지로 디버그로 Handler들이 잘 등록되었는지 살펴보자.

디버그 결과를 보면, 각각 다른 3가지 urlWelcomeController가 매핑되어 Handler로 등록되었음을 볼 수 있다.

💡 SimpleUrlHandlerMapping을 xml로 나타내보자

SimpleUrlHandlerMapping을 xml로 등록한다고 하면 아래와 같이 표현 할 수 있다.

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/simpleUrlWelcome">welcome</prop>
            <prop key="/anotherUrlWelcome">welcome</prop>
            <prop key="/otherUrlWelcome">welcome</prop>
        </props>
    </property>
</bean>
<bean id="welcome" class="com.example.WelcomeController" />
...

SimpleUrlHandlerMapping 내부코드 살펴보기

SimpleUrlHandlerMapping은 개발자가 직접적으로 선언한 keyvalue를 통해서 HandlerMapping을 초기화 한다.
그래서 가장 먼저 xml에서 개발자가 선언한 설정 값들을 읽어와 Handler들을 등록할 준비를 해야한다.

위 코드가 바로 SimpleUrlHandlerMapping에 등록할 Handler들을 설정파일로 부터 읽어오는 코드이다.

바로 앞에서 살펴본 xml 파일을 다시 보자.

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/simpleUrlWelcome">welcome</prop>
            <prop key="/anotherUrlWelcome">welcome</prop>
            <prop key="/otherUrlWelcome">welcome</prop>
        </props>
    </property>
</bean>
<bean id="welcome" class="com.example.WelcomeController" />
...

property 부분을 보면 name=mappings로 되어있다. 그리고 SimpleUrlHandlerMappingsetMappings() 메서드를 보면 파라미터로 Properties 객체를 mappiongs라는 이름으로 받아온다.

바로 xml파일에서 name=mappings 부분을 읽어오는 것이다.

즉, xml파일의 keyvalue를 통해서 SimpleUrlHandlerMapping에 등록할 Handler들을 준비하는 것 이다.

그리고 setMappings() 메서드의 CollectionUtils.mergePropertiesIntoMap()을 따라가보면
아래와 같다.

Properties의 값들을 읽어와서 Map 객체에 추가해주는 코드이다.

155번 줄을 보면 Map에 요소들을 추가해주고 있다.

CollectionUtils.mergePropertiesIntoMap() 반환 값인 Map을 통해서 SimpleUrlHandlerMapping은 등록할 Handler들이 어떤것들 인지를 초기화한다.

다시 돌아와서 정리해보자. SimpleUrlHandlerMappingsetMappings() 메서드를 통해 xml 파일의 property 부분을 읽어오고 property 내부의 urlbean을 필드인 urlMap에 넣어준다.

위 사진은 SimpleUrlHandlerMapping의 필드인 urlMap이다.
urlMapSimpleUrlHandlerMappinginitApplicationContext()에 사용된다.

❓❓ setMappings() 메서드는 어느시점에 호출될까?

SimpleUrlHandlerMappinginitApplicationContext() 메서드가 호출 될 때 필드인 handlerMap에 적절한 Handler 들을 초기화한다.

아래에서 자세히 살펴보겠지만, SimpleUrlHandlerMappinginitApplicationContext()를 호출 할 때는 이미 초기화 된 urlMap을 통해서 Handler들을 handlerMap에 등록한다.

그렇다면, SimpleUrlHandlerMappingsetMappings() 메서드는 어느시점에 호출 될까?
이 부분은 예상이 잘 되지 않지만 ApplicationContext를 최초로 읽어 Bean을 생성하는 시점이 아닐까 추측해본다.😮


SimpleUrlHandlerMapping의 Handler 초기화

SimpleUrlHandlerMappinginitApllicationContext()를 통해 부모객체인 AbstractUrlHandlerMappinghandlerMap 필드를 초기화한다.

우선 저번 포스팅에서 super.initApllicationContext()를 다뤘기 때문에 간략하게 넘어가겠다.
138번 줄의 부모 클래스 initApllicationContext()를 통해 interceptor를 초기화한다.

그런데, SimpleUrlHandlerMappingBeanNameUrlHandlerMapping과 다르게 registerHandlers() 라는 메서드를 통해 handlerMap에 등록될 Handler들을 초기화한다.

registerHandlers()를 따라가 보면 위에서 살펴보았던 urlMap을 for문을 돌면서 Handler들을 등록해줌을 알 수 있다.

한가지 특이한 점은 155번줄과 같이 url 형식이 잘못되어도 에러를 발생하지 않고 형식을 맞춰준다는 점이다.😮

이어서 162번 줄의 registerHandler() 메서드를 따라가 보자.

registerHandler()를 따라가면 부모 클래스인 AbstractUrlHandlerMappingregisterHandler() 메서드를 통해서 Handler들을 handlerMap 필드에 추가해줌을 알 수 있다.

마찬가지로 저번 포스팅에서 살펴보았기 때문에 간략히만 살펴보자.

AbstractUrlHandlerMappingregisterHandler() 메소드는 446번 줄과 같이 handlerMaphandler들을 매핑해줌을 알 수 있다.

❓❓ urlMap에 Handler 들이 있는데, 왜 다시 부모 객체의 handlerMap필드에 등록 시켜줄까?

SimpleUrlHandlerMappingurlMap 필드에 Handler들을 들고 있다.
그런데, 굳이 부모 객체인 AbstractUrlHandlerMappinghandlerMapurlMap에 있는 Handler들을 등록시켜준다.

그 이유는, DispatcherServletHandlerMapping을 통해 Handler를 가져오는 메서드를
AbstractHandlerMappinggetHandler() 메서드 하나로 통일하기 위해서가 아닐까 싶다.

실제로 SimpleUrlHandlerMappingBeanNameUrlHandlerMapping 모두 AbstractHandlerMappinggetHandler()를 통해서 적절한 HandlerDispatcherServlet에게 전달한다.

SimpleUrlHandlerMapping의 Handler를 DispatcherServlet에 전달하는 과정

마찬가지로 이전 포스팅에서 다뤘으며 과정이 완전히 동일 하기 때문에 넘어가겠다.

BeanNameHandlerMapping과 Handler를 DispatcherServlet에 전달하는 과정

마치면서

이상으로 SimpleUrlHandlerMapping 에 대해서 살펴보았다.
글을 정리하면서 느낀점은 이 글만으로는 SimpleUrlHandlerMapping에 대한 이해에 큰 도움이 되지 않겠다는 점이다😔

그래도 다른 분들이 실제 코드를 들여다 볼때, 조금이나마 도움이 되었으면 좋겠다😊

profile
천천히 배워가는 개발꿈나무

0개의 댓글