HandlerMapping
이 Spring
에서 어떤 역할을 하는지에 대해서 이전 포스팅에서 다뤄 보았다.
그래서 이번 포스팅에서는 이 부분에 대해서 건너뛰고 SimpleUrlHandlerMapping
에 대해서 살펴보자.
HandlerMapping과 BeanNameUrlHandlerMapping 살펴보기
SimpleUrlHandlerMapping
은 빈 인스턴스와 URL 또는 빈 이름과 URL 간의 직접적이고 선언적인 매핑을 통해 Handler
들을 등록하는 HandlerMapping
이다.
코드를 통해 위 설명을 살펴보자.
우선, 위와 같이 SimpleUrlHandlerMapping
을 빈 등록해준다. 그리고 Map<String, Object>
에 url
을 key, handler
를 value로 값을 넣어준다.
그리고 18번 줄과 같이 simpleUrlHandlerMapping.setUrlMap()
을 호출해주면 SimpleUrlHandlerMapping
에 WelcomeController
가 Handler
로 등록될 것이다.
테스트 코드 디버그를 통해 SimpleUrlHandlerMapping
에 Handler
가 잘 등록되었는지 살펴보자.
위 코드는 SimplerHandlerMapping
이 필드인 HandlerMap
에 예상한 Handler
를 가지고 있는지 확인하기 위한 테스트 코드이다.
디버그를 통해 확인해보면SimpleUrlHandlerMapping
의 handlerMap
에 key
와 value
가 각각 "/simpleUrlWelcome"
, WelcomeController
로 예상과 같이 설정 되었음을 알 수 있다.
이제 다시 SimpleUrlHandlerMapping
에 대한 처음 설명을 보면 쉽게 이해가 된다.
SimpleUrlHandlerMapping
은 빈 인스턴스와 URL 또는 빈 이름과 URL 간의 직접적이고 선언적인 매핑을 통해Handler
들을 등록하는HandlerMapping
이다.
SimpleUrlHandlerMapping
은 빈 인스턴스와 URL
을 직접적이고 선언적인 매핑을 한다고 말한다.
처음의 @Configuration
코드를 다시보자.
위 코드를 보면 개발자가 WelcomeController
라는 Handler
와 "/simpleUrlWelcome"
이라는 url
을 직접적이고 선언적으로 코드에 나타내었음을 볼 수 있다.
그래서 SimpleUrlHandlerMapping
은 가장 유연한 HandlerMapping
이라고도 한다.
개발자가 직접적으로 설정하는 부분이 가장 많기 때문이다.
SimpleUrlHandlerMapping
은 직접적이고 선언적인 HandlerMapping
인 만큼 한가지 특징을 가진다.
바로, 한가지 Handler
에 여러가지 url
을 매핑하기 쉽다는 것이다.
코드를 통해 살펴보자.
위 코드를 보면 WelcomeController
에 3가지의 url
을 매핑했음을 알 수 있다.
마찬가지로 디버그로 Handler
들이 잘 등록되었는지 살펴보자.
디버그 결과를 보면, 각각 다른 3가지 url
에 WelcomeController
가 매핑되어 Handler
로 등록되었음을 볼 수 있다.
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
은 개발자가 직접적으로 선언한 key
와 value
를 통해서 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
로 되어있다. 그리고 SimpleUrlHandlerMapping
의 setMappings()
메서드를 보면 파라미터로 Properties
객체를 mappiongs
라는 이름으로 받아온다.
바로 xml
파일에서 name=mappings
부분을 읽어오는 것이다.
즉, xml
파일의 key
와 value
를 통해서 SimpleUrlHandlerMapping
에 등록할 Handler
들을 준비하는 것 이다.
그리고 setMappings()
메서드의 CollectionUtils.mergePropertiesIntoMap()
을 따라가보면
아래와 같다.
Properties
의 값들을 읽어와서 Map
객체에 추가해주는 코드이다.
155번 줄을 보면 Map
에 요소들을 추가해주고 있다.
CollectionUtils.mergePropertiesIntoMap()
반환 값인 Map
을 통해서 SimpleUrlHandlerMapping
은 등록할 Handler
들이 어떤것들 인지를 초기화한다.
다시 돌아와서 정리해보자. SimpleUrlHandlerMapping
은 setMappings()
메서드를 통해 xml
파일의 property
부분을 읽어오고 property
내부의 url
과 bean
을 필드인 urlMap
에 넣어준다.
위 사진은 SimpleUrlHandlerMapping
의 필드인 urlMap
이다.
urlMap
은 SimpleUrlHandlerMapping
의 initApplicationContext()
에 사용된다.
SimpleUrlHandlerMapping
은 initApplicationContext()
메서드가 호출 될 때 필드인 handlerMap
에 적절한 Handler
들을 초기화한다.
아래에서 자세히 살펴보겠지만, SimpleUrlHandlerMapping
이 initApplicationContext()
를 호출 할 때는 이미 초기화 된 urlMap
을 통해서 Handler
들을 handlerMap
에 등록한다.
그렇다면, SimpleUrlHandlerMapping
의 setMappings()
메서드는 어느시점에 호출 될까?
이 부분은 예상이 잘 되지 않지만 ApplicationContext
를 최초로 읽어 Bean
을 생성하는 시점이 아닐까 추측해본다.😮
SimpleUrlHandlerMapping
은 initApllicationContext()
를 통해 부모객체인 AbstractUrlHandlerMapping
의 handlerMap
필드를 초기화한다.
우선 저번 포스팅에서 super.initApllicationContext()
를 다뤘기 때문에 간략하게 넘어가겠다.
138번 줄의 부모 클래스 initApllicationContext()
를 통해 interceptor
를 초기화한다.
그런데, SimpleUrlHandlerMapping
은 BeanNameUrlHandlerMapping
과 다르게 registerHandlers()
라는 메서드를 통해 handlerMap
에 등록될 Handler
들을 초기화한다.
registerHandlers()
를 따라가 보면 위에서 살펴보았던 urlMap
을 for문을 돌면서 Handler
들을 등록해줌을 알 수 있다.
한가지 특이한 점은 155번줄과 같이 url
형식이 잘못되어도 에러를 발생하지 않고 형식을 맞춰준다는 점이다.😮
이어서 162번 줄의 registerHandler()
메서드를 따라가 보자.
registerHandler()
를 따라가면 부모 클래스인 AbstractUrlHandlerMapping
의 registerHandler()
메서드를 통해서 Handler
들을 handlerMap
필드에 추가해줌을 알 수 있다.
마찬가지로 저번 포스팅에서 살펴보았기 때문에 간략히만 살펴보자.
AbstractUrlHandlerMapping
의 registerHandler()
메소드는 446번 줄과 같이 handlerMap
에 handler
들을 매핑해줌을 알 수 있다.
SimpleUrlHandlerMapping
은 urlMap
필드에 Handler
들을 들고 있다.
그런데, 굳이 부모 객체인 AbstractUrlHandlerMapping
의 handlerMap
에 urlMap
에 있는 Handler
들을 등록시켜준다.
그 이유는, DispatcherServlet
이 HandlerMapping
을 통해 Handler
를 가져오는 메서드를
AbstractHandlerMapping
의 getHandler()
메서드 하나로 통일하기 위해서가 아닐까 싶다.
실제로 SimpleUrlHandlerMapping
와 BeanNameUrlHandlerMapping
모두 AbstractHandlerMapping
의 getHandler()
를 통해서 적절한 Handler
를 DispatcherServlet
에게 전달한다.
마찬가지로 이전 포스팅에서 다뤘으며 과정이 완전히 동일 하기 때문에 넘어가겠다.
BeanNameHandlerMapping과 Handler를 DispatcherServlet에 전달하는 과정
이상으로 SimpleUrlHandlerMapping
에 대해서 살펴보았다.
글을 정리하면서 느낀점은 이 글만으로는 SimpleUrlHandlerMapping
에 대한 이해에 큰 도움이 되지 않겠다는 점이다😔
그래도 다른 분들이 실제 코드를 들여다 볼때, 조금이나마 도움이 되었으면 좋겠다😊