홍이의 개발 노트

Spring MVC 3.1 에서 달라진 <mvc:annotation-driven/> 전략 본문

개발이야기/스프링(Spring)

Spring MVC 3.1 에서 달라진 <mvc:annotation-driven/> 전략

코바 2012. 4. 19. 13:16

기존 Spring MVC 3.0.x의 <mvc:annotation-driven/> 태그의 전략은 

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

클래스를 사용하여 맵핑 및 여러 클래스를 추가하여 구성이 되었다.


하지만 이번 3.1 버전이 나오며 이야기가 달라졌다.

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

이 두개의 클래스가 주축이 되면서 기능 및 구성이 달라지고 

기존과는 거의 호환이 되게 만들졌다.


기존의 전략은 박성철님 블로그 ( http://gyumee.egloos.com/3056225 ) 여기에서 보는 것과 같이 구성되어 있었다.

하지만 3.1은 조금 달라졌다.

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

<property name="order" value="0" />

</bean>


<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />


<!-- <mvc:message-converters> 태그의 messageConverter와 통합 -->

<util:list id="messageConverters">

<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />

<bean class="org.springframework.http.converter.StringHttpMessageConverter">

<property name="writeAcceptCharset" value="false" />

</bean>

<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />

<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />

<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" />

<!-- jaxb2라이브러리 존재시 -->

<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />

<!--  -->

<!-- jackson 라이브러리 존재시 -->

<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>

<!--  -->

<!-- rome 라이브러리 존재시 -->

<bean class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter" />

<bean class="org.springframework.http.converter.feed.RssChannelHttpMessageConverter" />

<!--  -->

</util:list>


<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<property name="webBindingInitializer">

<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">

<property name="validator" ref="validator" />

<property name="conversionService" ref="conversion-service" />

</bean>

</property>

<property name="messageConverters" ref="messageConverters"/>

<!-- <mvc:argument-resolvers> 태그 존재시 -->

<!--

<property name="customArgumentResolvers">

</property>

-->

<!-- <mvc:return-value-handlers> 태그 존재시 -->

<!--

<property name="customReturnValueHandlers">

</property>

-->

</bean>


<bean class="org.springframework.web.servlet.handler.MappedInterceptor">

<constructor-arg index="0">

<null />

</constructor-arg>

<constructor-arg index="1">

<bean class="org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor">

<constructor-arg index="0" ref="conversion-service" />

</bean>

</constructor-arg>

</bean>


<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">

<property name="messageConverters" ref="messageConverters"/>

<property name="order" value="0"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver">

<property name="order" value="1"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver">

<property name="order" value="2"/>

</bean>

이렇게 변경이 되었다 

먼저 변경된  부분만 이야기하면 

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

이 두 부분이 바뀐것이 가장 큰 변화이고 

그다음은 customArgumentResolvers 이 속성의 인터페이스가 변경 되었다.

기존에는 WebArgumentResolver인터페이스를 상속 받았으나 3.1부터는 HandlerMethodArgumentResolver 인터페이스를 상속 받아 구현을 해야한다. 

하지만 <mvc:annotation-driven/> 여기서 등록시에는 기존 WebArgumentResolver 이부분을 구현한 클래스가 사용은 가능하다. 내부적으로 ServletWebArgumentResolverAdapter 클래스를 사용하여 호환 가능하게 변경을 해준다. 

하지만 생각지 못한 버그가 발생할 수 있으니 변경된 인터페이스를 적용하는 것을 추천한다.


그리고 customModelAndViewResolvers 이 속성 또한 변경되었다. 

기존에는 ModelAndViewResolver인터페이스를 상속 받았으나 3.1부터는 HandlerMethodReturnValueHandler 인터페이스를 상속받아 구현해야한다.

이름은 customReturnValueHandlers 속성의 이름으로 변경되었으며 WebArgumentResolver와 같이 인터페이스도 변경되었다. 


추가로 로딩되는 Bean으로는 

<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">

<property name="messageConverters" ref="messageConverters"/>

<property name="order" value="0"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver">

<property name="order" value="1"/>

</bean>

<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver">

<property name="order" value="2"/>

</bean>

이렇게 3개의 Bean이 로딩이 된다 

첫번째 로딩되는 Bean인 ExceptionHandlerExceptionResolver 클래스는 RequestMappingHandlerAdapter 에서 참조 하는 messageConverters를 똑같이 참조하고 있다. 

용도를 정확히는 확인해보지는 않았지만 대략 @RequestBody의 @Valid 어노테이션을 사용할 수 있는 것과 관계 있는 것으로 보인다. 
이부분은 추후로 보완할 예정이다.