캠핑과 개발

annotation-driven +1

<mvc:annotation-driven>은 @MVC 스타일의 컨트롤러에서 자주 사용되는 validator, conversionService, messageConverter를 자동으로 등록해주는 간편 빈 설정용 태그이다.

이 태그에 의해서 자동으로 등록되는 기능들에 대해서는 3.0.1의 보강된 레퍼런스 문서에 다음과 같이 잘 나와있다.

  1. Support for Spring 3′s Type ConversionService in addition to JavaBeans PropertyEditors during Data Binding. A ConversionService instance produced by the org.springframework.format.support.FormattingConversionServiceFactoryBean is used by default. This can be overriden by setting the conversion-service attribute.
  2. Support for formatting Number fields using the @NumberFormat annotation
  3. Support for formatting Date, Calendar, Long, and Joda Time fields using the @DateTimeFormat annotation, if Joda Time is present on the classpath.
  4. Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath. The validation system can be explicitly configured by setting the validator attribute.
  5. Support for reading and writing XML, if JAXB is present on the classpath.
  6. Support for reading and writing JSON, if Jackson is present on the classpath.

그런데 과연 이게 전부일까?

아니다.

<mvc:annotation-driven>이 등록해주는 빈이 한가지 더 있다. 바로 MappedInterceptor이다. 정확히 말하자면 모든 경로에 대해서 적용되는 ConversionServiceExposingInterceptor를 가진 MappedInterceptor이다.

아직 많은 개발자들에게는 MappedInterceptor도 3.0에서 새로 추가된 것이라 생소할 것이다. 기존 HandlerInterceptor는 핸들러 매핑의 프로퍼티로 등록된다. 이 때문에 두 가지 단점이 있는데, 첫 째는 핸들러 매핑 전략을 두 개 이상을 병행해서 사용하면 인터셉터를 일일히 핸들러 매핑마다 등록해줘야 한다는 점이다. 둘 째는 핸들러 매핑에 등록한 인터셉터는 그 핸들러 매핑이 처리하는 모든 요청에 적용된다는 점이다. URL에 따라 적용 인터셉터를 선별하려면 인터셉터 안에서 URL을 필터링 하는 작업을 해야 한다.

MappedInterceptor는 이 두가지 단점을 보완해주는 새로운 인터셉터 적용방식이다. MappedInterceptor를 빈으로 등록하고 path와 interceptor를 지정해주면 해당 경로패턴에 일치하는 URL에 대해서는 어떤 핸들러 매핑을 이용하든 상관없이 지정한 인터셉터를 적용해준다. 일종의 글로벌 스마트 인터셉터 레지스트리라고나 할까. 이 MappedInterceptor의 등장으로 앞으로는 핸들러 매핑에 인터셉터를 등록해서 사용할 일은 없을 듯 하다.

아무튼, <mvc:annotation-driven>는 뜬금없이 이 MappedInterceptor를 등록해버린다. 그것도 모든 경로에 대해서 적용한다. 추가된 인터셉터는 ConversionServiceExposingInterceptor라는 단순한 것인데, ConversionService 오브젝트를 request의 애트리뷰트에 등록해주는 간단한 작업을 수행한다. ConversionService라면 AnnotationMethodHandlerAdapter에 의해서 @ModelAttribute에 바인딩할 때 사용할 오브젝트이다. <mvc:annotation-driven>에서는 conversion-service 애트리뷰트에 의해서 재구성한 ConversionService를 지정할 수 있다.

<mvc:annotation-driven>는 바로 이 ConversionService를 request 스코프 애트리뷰트에 등록한다. 도데체 어디서 써먹으려는 것일까?

 

용도는 바로 <spring:eval>이다. 새롭게 추가된 <spring:eval>은 JSP에서 JSP EL을 대신해서 초강력 SpEL을 사용할 수 있도록 추가된 태그이다. 바로 이 <spring:eval>이 모델 오브젝트의 프로퍼티 값을 텍스트로 변환할 때 ConversionServiceExposingInterceptor에 의해서 등록된 ConversionService가 적용되는 것이다.

<mvc:annotation-driven>을 사용하지 않아서 ConversionService가 등록되지 않았다면 <spring:eval>은 기본적인 타입변환만 지원하는 StandardTypeConverter을 사용한다. 그보다는 ConversionServiceExposingInterceptor을 통해서 등록되는 FormattingConversionService가 훨씬 강력할 것이다. 모델에 @NumberFormat이나 @DateTimeFormat같은 포맷터가 달려있다면 <spring:eval>만으로도 이 포맷팅이 적용된다는 뜻이다.

기존에는 PropertyEditor가 적용되는 폼에서나 포맷을 가진 프로퍼티 바인딩을 적용할 수 있었다. 단순 출력을 필요로 하는 곳에서는 JSP EL을 사용해야 했기에 모델 오브젝트 프로퍼티의 포맷을 지정하려면 지저분한 <fmt:formatNumber> 따위의 태그를 사용해야만 했다. 그것도 몇가지 종류의 포맷밖에 지원이 안된다.

하지만 이제 3.0.1부터는 <spring:eval>을 사용해서 ConversionService의 막강한 타입변환-포맷팅 기능을 적용할 수 있다.

 

아직 레퍼런스나 API문서 등에도 공개되지 않은 내용인데.. 이런 중요한 정보를 미리미리 알려주지 않다니!

3.0.1의 막강한 @MVC와 ConversionService, Formatter, JSR-303 Bean Validation, Message Converter, AJAX 등등등을 활용한 편리한 웹 개발에 대해서 자세히 알고 싶다면 조만간 출시 예정인 스프링 3.0 책을 참고하도록… 



출처 : http://toby.epril.com/?p=989