본문 바로가기

프로그래밍/Spring

전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 1

저번 글까지는 Root Context 환경 설정 XML 파일을 Java Config 방식으로 변경하고 이를 web.xml에 등록해서 로딩하는 내용에 대해 설명했다. 이번 글에서부터는 Servlet Context 환경 설정 XML 파일을 Java Config 방식으로 변경하는 내용에 대해 설명하겠다. 이 부분에 대해서는 설명해야 할 내용이 좀 있는 관계로 글을 나누어서 설명하겠다

 

구체적으로 이 내용을 다루기 전에 Spring에서 Servlet Context 정확하게는 Spring MVC 환경을 Java Config 로 구성하는 방법에 대해 약간 짚고 넘어가야 한다. 왜냐면 이 내용을 얘기해야 앞으로 설명할 내용에 대한 부분을 왜 이렇게 하는지에 대한 설명이 된다. Spring MVC 환경을 Java Config 방식으로 설정하는 방법은 큰 틀에서 보면 다음의 3가지 중 하나를 선택하면 된다.

 

  • @EnableWebMvc 어노테이션을 환경 설정 클래스의 클래스 레벨에 붙인다
  • @EnableWebMvc 어노테이션을 붙여서 구성했으나 몇몇 구성에 대해서는 커스터마이징을 해야 한다면 클래스를 만들때 WebMvcConfigurerAdapter 클래스를 상속받아 구성한다
  • 두번째 방법으로 해결해야 하는게 아니라 아예 전면적으로 Spring MVC를 재구성을 해야 하는 경우에는 @EnableWebMvc 어노테이션을 빼고 WebMvcConfigurationSupport 클래스를 상속받아 전면 재구성을 진행한다

 

@EnableWebMvc 어노테이션을 붙이면 Spring에서는 내부적으로 WebMvcConfigurationSupport 클래스를 환경설정 클래스로 등록해서 Spring MVC 환경을 구성하게 된다. 이 WebMvcConfifurationSupport 클래스가 하는 역할은 주로 사용하는 HandlerMapping 인터페이스를 구현한 클래스들(ex : RequestMappingHandlerMapping 클래스)와 HandlerAdapter 인터페이스를 구현한 클래스들(ex : RequestMappingHandlerAdapter 클래스), 예외 처리 관련 ExceptionResolver 클래스들이 등록되어진 HandlerExceptionResolverComposite 클래스 등 Spring Web MVC 환경을 구성하는 클래스들을 등록하는 작업을 진행한다. 그러나 어떤 프로젝트든 이 환경을 그냥 사용하는 경우는 별로 없는 편이다. Interceptor를 추가할 수도 있고 Converter를 추가할 수도 있다. 그럴때는 @EnableWebMvc 어노테이션을 붙이면서 WebMvcConfigurerAdapter 클래스를 상속받은 클래스로 환경 설정 클래스를 만든뒤 이 클래스에서 제공하는 메소드를 이용해서 관련 작업을 진행한다. 만약 @EnableWebMvc 어노테이션이 등록해주는 환경 자체를 부정하고 아예 전면 재구성을 해야 한다면 @EnableWebMvc 어노테이션을 제거하고 WebMvcConfigurationSupport 클래스를 상속받아 여기에서 제공하는 메소드를 override 해서 설정 자체를 바꿔버리면 된다. WebMvcConfigurationSupport 클래스를 보면 위에서 방금 언급했던 각종 클래스들을 만드는 메소드들이 있기 때문에 그 메소드를 override 해서 해당 클래스의 설정값을 그 메소드에서 아예 바꿔서 만들어버릴수 있다. 자세한 내용은 Spring Framework Javadoc API 문서에서 @EnableWebMvc 어노테이션과 WebMvcConfigurationSupport 클래스에 대한 내용을 보면 알 수 있다.

 

이러한 내용을 먼저 이해하고 Servlet Context 환경 설정을 구성하는 dispatcher-servlet.xml을 Java Config 방식으로 바꾸는 방법을 진행해보도록 하자. 먼저 dispatcher-servlet.xml을 보면 Spring에서 기본적으로 제공하는 Spring MVC를 이용하고 있지가 않다. Spring에서 XML로 환경설정 할 때 <mvc:annotation-driven />을 사용하면 위에서 언급했던 @EnableWebMvc 같은 기본적인 Spring MVC 기본 셋팅을 하는 작업을 진행한다(@EnableWebMvc가 하는 작업과는 약간 차이는 존재한다) 그러나 전자정부 프레임워크에서 제공하는 Sample 프로젝트에서는 <mvc:annotation-driven /> 어노테이션을 사용하지 않았다. 그래서 Spring MVC를 하기 위해 필요한 클래스들을 직접 Spring bean으로 등록해야 한다. 그 첫번째 주자인 RequestMappingHandlerMapping 클래스 설정을 보도록 하자. dispatcher-servlet.xml에서 RequestMappingHandlerMapping 클래스는 다음과 같이 bean으로 선언되어 있다.

 

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="webBindingInitializer">
		<bean class="egovframework.example.cmmn.web.EgovBindingInitializer"/>
	</property>
</bean>

 

위의 XML 설정이 하는 내용은 단순하다. RequestMappingHandlerAdapter 클래스를 생성한 뒤에 webBindingInitializer 속성에 전자정부 프레임워크에서 제공하는 EgovBindingInitializer 클래스를 설정하고 있다. 그러면 이제 이 부분을 Java Config 방식으로 바꾸어 보자. RequestMappingHandlerAdapter는 위에서 언급했다시피 @EnableWebMvc 어노테이션을 붙이면 Spring에서 자동으로 이 클래스를 bean 객체로 등록을 시켜준다. 문제는 webBindingInitializer를 다른 클래스로 대체할 수 있는(Spring은 기본적으로 이 속성에 ConfigurableWebBindingInitializer 클래스 객체를 등록한다) 방법이다. 이 부분을 위에서 얘기했던 @EnableWebMvc 어노테이션을 붙인 상태에서 WebMvcConfigureAdapter 클래스를 상속 받는 형태로 커스터마이징을 할 수 있는가를 알아봐야 한다. 그러나 이 방법으로는 저 부분을 커스터마이징을 할 수 없다. WebMvcConfigureAdapter에서 override 가능한 메소드 중에 저 부분을 수행할 수 있는 메소드가 없기 때문이다(이 부분은 Spring Framework API Javadoc 문서에서 WebMvcConfigureAdapter 클래스를 보면 알 수 있다) 그래서 이 부분을 할려면 @EnableWebMvc 어노테이션을 붙이지 않고 WebMvcConfigurationSupport를 상속받아 RequestMappingHandlerAdapter 클래스를 만드는 메소드를 override 해서 커스터마이징 하는 방법으로 가야 한다. 다음과 같이 말이다.

 

@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
	// TODO Auto-generated method stub
	RequestMappingHandlerAdapter rmha = super.requestMappingHandlerAdapter();
	rmha.setWebBindingInitializer(new EgovBindingInitializer());
	return rmha;
}

 

위의 코드를 보면 requestMappingandlerAdapter 메소드를 override 했고 이 메소드에 @Bean 어노테이션을 붙였기 때문에 bean id가 메소드 이름이 된다는 규칙에 따라 id가 requestMappingHandlerAdapter인 Spring bean을 등록한다는 것을 알 수 있다. 내부 코드를 보면 RequestMappingHandlerAdapter 클래스 객체를 생성하는 것을 볼 수 있는데 new로 생성하지 않고 부모클래스의 것을 다시 재활용했다. 왜 이리 했냐면 부모클래스에서 제공하는 것이 Spring Web Mvc에서 필요한 셋팅을 더 해주기 때문이다. 객체만 생성하는 식으로 가버리면 RequestMappingHandlerAdapter 클래스에 대한 부가적인 환경 설정이 안되어 버리기 때문에 이런 환경들이 같이 셋팅되게끔 해서 사용하기 편하게끔 해주었다. 그리고 부모클래스에서 제공되는 메소드를 이용해 생성한 객체에 setWebBindingInitializer 메소드를 이용해 위에서 언급했던 EgovBindingInitializer 클래스 객체 생성하고 이를 셋팅해준뒤 RequestMappingHandlerAdapter 클래스 객체를 return 해주고 있다. 지금까지 글들을 잘 따라온 사람이면 위의 XML과 자바 코드에 대한 이해가 그리 어렵진 않을 것이다.

 

그럼 다음의 XML을 보자.

 

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="localeChangeInterceptor" />
		</list>
	</property>
</bean>

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />
<!-- 쿠키를 이용한 Locale 이용시 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/> -->
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
	<property name="paramName" value="language" />
</bean>

 

만들어지는 XML이 이렇게 나오는 바람에 중간에 SessionLocaleResolver Bean을 등록 <bean> 태그가 있지만 이 XML을 통해서 얘기하고자 하는 것은 Interceptor를 등록하는 부분이다. RequestMappingHandlerMapping 클래스를 bean으로 등록할 때 Interceptor를 등록하고 있는데 이때 LocaleChangeInterceptor 클래스 bean을 설정하고 있다. 즉 이 XML에서 하듯이 Java Config 방식으로 Interceptor를 등록해야 하는 것이다. 여기서는 RequestMappingHandlerMapping 클래스를 직접 bean으로 설정하고 Interceptor만 다시 재설정하고 있으나 이렇게 할 경우 부가적인 환경설정이 자동으로 이루어지지 않기 때문에 RequestMappingHandlerMapping 클래스를 생성하는 부분이 있는 WebMvcConfigurationSupport 클래스에서 생성이 되는 것을 그대로 이용하고 Interceptor만 다시 재설정하는 방향으로 가는것이 좋다. 그러면 어떻게 해야 이러한 방법으로 갈 수 있을까? WebMvcConfigurationSupport 클래스는 사용자가 Interceptor를 추가할 수 있게끔 addInterceptors란 메소드를 제공하고 있다. 이 메소드를 이용하여 WebMvcConfigurationSupport 클래스가 생성하는 RequestMappingHandlerMapping 클래스 bean에 Interceptor만 추가할 수 있다. 위의 XML을 Java Config 방식으로 바꾸면 다음과 같이 바꿀수 있다.

 

@Override
protected void addInterceptors(InterceptorRegistry registry) {
	registry.addInterceptor(localeChangeInterceptor());
}

@Bean
public SessionLocaleResolver localeResolver(){
	SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
	return sessionLocaleResolver;
}

/*
// 쿠키를 이용한 Locale 이용시 이 부분을 주석처리를 풀어서 사용하고 위에 있는 SessionLocaleResolver 클래스를 사용하는
// @Bean 메소드는 주석처리 한다
@Bean
public CookieLocaleResolver localeResolver(){
	CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
	return cookieLocaleResolver;
} 
 */

@Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
	LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
	localeChangeInterceptor.setParamName("language");
	return localeChangeInterceptor;
}

 

RequestMappingHandlerMapping 클래스 bean은 WebMvcConfigurationSupport 클래스에서 만들어주는 것을 사용하기 때문에 그것을 override 해서 별도로 설정할 필요가 없다. 그래서 그 부분은 건드리지 말고 Interceptor로 등록할 LocaleChangeInterceptor 클래스 bean을 만들어주는 localeChangeInterceptor 메소드를 만들고 Interceptor를 추가하는 method인 addInterceptors 메소드에서 localeChangeInterceptor 메소드를 호출하는 식으로 LocaleChangeInterceptor 클래스 bean을 Interceptor로 추가했다.

 

이번 글에서는 Java Config 방식으로 Spring MVC 환경 설정하는 방법 중 RequestMappingHandlerAdapter 클래스 설정의 커스터마이징 방법과 사용자 정의 Interceptor를 추가하는 방법에 대해 설명했다. 다음에는 Java Config 방식으로 HandlerExceptionResolver를 설정하는 방법에 대해 설명하도록 하겠다

 

 

목     차

 1. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(환경구축)

 2. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(기초)

 3. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-aspect.xml 변환)

 4. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-common.xml 변환)

 5. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-datasource.xml 변환)

 6. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-sqlMap.xml, context-mapper.xml 변환)

 7. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-transaction.xml 변환)

 8. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(context-idgen.xml, context-properties.xml, context-validator.xml 변환)

 9. 작성된 Java Config 클래스 파일들을 실제 등록해보자(RootContext 클래스 제작)

 10. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 1

 11. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 2

 12. 전자정부 프레임워크를 Java Config 방식으로 설정해보자(dispatcher-servlet.xml 변환) - 3