Spring : WebApplicationInitializer / AbstractAnnotationConfigDispatcherServletInitializer

WebApplicationInitializer / AbstractAnnotationConfigDispatcherServletInitializer

기존의 xml을 이용한 설정과는 다른 어노테이션만을 이용한 설정 방법입니다.

Spring MVC는 ServletContainerInitializer를 구현하고 있는 SpringServletContainerInitializer를 제공합니다. SpringServletContainerInitializer는 WebApplicationInitializer 구현체를 찾아 인스턴스를 만들고 해당 인스턴스의 onStartup 메소드를 호출하여 초기화합니다.

AbstractAnnotationConfigDispatcherServletInitializerWebApplicationInitializer 를 상속받았기 때문에 AbstractAnnotationConfigDispatcherServletInitializer도 구현체라고 할 수 있습니다.

차이점

WebApplicationInitializeronStartup()함수 안에 DispatcherServletContextLoaderListener를 모두 구현해야합니다.

하지만 AbstractAnnotationConfigDispatcherServletInitializer는 내부적으로 startUp, registDispatcherServlet을 진행합니다.

코드를 보면 딱 차이점이 느껴질 것이기 때문에 코드를 보며 알아보겠습니다.

ApplicationConfigLayered Architecture에서 Service LayerRepository Layer를 모아놓은 것입니다.(root-conifg 관련 파일, 안에 DB설정 관련 파일인 DBConfigimport하고 있습니다.)

WebMvcContextConfigurationDispatcherServlet 등의 servlet-config 관련 파일입니다.

Listner 설정

XML방식

기존의 XML을 이용한 Listner 설정 방법입니다.

  <!-- context가 로딩될 때 이부분을 읽어서 수행하게 됩니다. -->
  <listener>
  	<listener-class>
  		org.springframework.web.context.ContextLoaderListener
  	</listener-class>
  </listener>

  <!-- listener에서 java Configuration을 이용하려면 이부분이 꼭 필요합니다!! -->
  <context-param>
  	<param-name>contextClass</param-name>
  	<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>

  <!-- 공통으로 사용할 Config 파일을 가져옵니다. -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>kr.or.connect.mvcguestbook.config.ApplicationConfig</param-value>
  </context-param>

WebApplicationInitializer

DispatcherServletListner를 사용할 때, AnnotationConfigWebApplicationContext 객체를 만들어야 하기 때문에 AnnotationConfigWebApplicationContext객체를 만드는 부분을 따로 함수(createContext)로 만들었습니다.

	// 인자로 받은 클래스로 AnnotationConfigWebApplicationContext를 만듭니다. 
	private AnnotationConfigWebApplicationContext createContext(final Class<?>... annotatedClasses) {
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.register(annotatedClasses);
		return context;
	}

	// 리스너를 생성하는 함수입니다. Override된 onStartup() 함수에서 호출해야 합니다.
	private void registerListener(ServletContext servletContext) {
		// ApplicationConfig(java Configuration)를 이용해 AnnotationConfigWebApplicationContext을 만들고 
		AnnotationConfigWebApplicationContext context = createContext(ApplicationConfig.class);
        // Listener에 context-param을 등록해 줍니다.
		servletContext.addListener(new ContextLoaderListener(context));
	}

AbstractAnnotationConfigDispatcherServletInitializer

AbstractAnnotationConfigDispatcherServletInitializergetRootConfigClasses()Override하여, Config파일만 지정해주면 내부적으로 알아서 root-config를 설정해줍니다.

	@Override
	protected Class<?>[] getRootConfigClasses() {
        // 배열로 되어있기 때문에 ','로 여러개의 Config파일을 지정할 수 있습니다.
		return new Class<?>[] {ApplicationConfig.class};
	}

DispatcherServlet 설정

XML방식

<servlet>
    <servlet-name>mvc</servlet-name>
    <!-- Spring이 제공하고 있는 DispatcherServlet을 FrontController로 할 것이라는 <servlet-class>가 등록되어 있습니다. -->
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    	<param-name>contextClass</param-name>
    	<!-- DispatcherServlet이 실행될 때 AnnotationConfigWebApplicationContext를 사용하기 위해 등록되어 있습니다. -->
    	<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
     	<param-name>contextConfigLocation</param-name>
    	<!-- DispatcherServlet이 실행될 때 설정들을 읽어야 하기 때문에 -->
    	<!-- <init-param>부분에 우리가 만든 WebMvcContextConfiguration를 설정하고 있는 것을 볼 수 있습니다. -->
    	<param-value>kr.or.connect.mvcguestbook.config.WebMvcContextConfiguration</param-value>
    </init-param>    
    <!-- 프로그램 시작과 동시에 서블릿의 생성과 초기화를 진행할 때 사용합니다. -->
    <!-- 여러 서블릿들간에 우선순위가 필요한 경우 0에 가까울수록 먼저 초기화가 진행됩니다. -->
    <load-on-startup>1</load-on-startup>
</servlet>
	<servlet-mapping>
        <!-- "/"요청이 들어오면 <servlet>안에 있는 <servlet-name>이 "mvc"인 이름을 찾아갑니다. -->
    	<servlet-name>mvc</servlet-name>
	    <url-pattern>/</url-pattern>
  </servlet-mapping>

WebApplicationInitializer

setLoadOnStartup()함수를 이용해 우선순위를 지정해주고, addMapping()함수로 url-pattern을 지정해줍니다.

	// DispatcherServlet를 만들어 줍니다.
	private void registerDispatcherServlet(ServletContext servletContext) {
        // WebMvcContextConfiguration(java Configuration)를 이용해 AnnotationConfigWebApplicationContext을 만들고
		AnnotationConfigWebApplicationContext context = createContext(WebMvcContextConfiguration.class);
		
        // DispatcherServlet를 만든 후, 서블릿들 간의 우선순위를 정해주고, url-pattern을 지정해줍니다.
		ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
		dispatcher.setLoadOnStartup(1);
		dispatcher.addMapping("/");
	}

AbstractAnnotationConfigDispatcherServletInitializer

AbstractAnnotationConfigDispatcherServletInitializergetServletConfigClasses()Override하여, Config파일만 지정해주면 내부적으로 알아서 DispatcherServlet설정을 해줍니다.

getServletMappings()Override하여 url-pattern을 지정해줍니다.

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class<?>[] {WebMvcContextConfiguration.class};
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] {"/"};
	}

Filter 설정

데이터를 주고 받을 때 한글이 제대로 나오게 하기위한 Filter설정도 해주어야합니다.

XML방식

<filter>
	<filter-name>encodingFilter</filter-name>
    <filter-class>
        org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <!-- 이 필터의 적용범위를 설정해줍니다. "/*"는 모든 범위, 특정 URL에만 지정할 수도 있습니다. -->
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 데이터를 주고 받을 때 한글이 제대로 나오게 해줍니다. -->

WebApplicationInitializer

	// 필터를 만듭니다.
	private void registerFilter(ServletContext servletContext) {
        // CharacterEncodingFilter 인자의 true, true는 request, response이 존재할 때 encoding을 적용한다는 것입니다.
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter("UTF-8", true, true);
		FilterRegistration.Dynamic webEncodingFilter = servletContext.addFilter("webEncodingFilter", encodingFilter);
		webEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
	}

AbstractAnnotationConfigDispatcherServletInitializer

	@Override
	protected Filter[] getServletFilters() {
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        // request와 response에 encoding을 적용한다는 것입니다.
        encodingFilter.setForceEncoding(true);

        return new Filter[]{encodingFilter};
	}

전체 코드

코드를 비교했을 때, 딱 봐도 AbstractAnnotationConfigDispatcherServletInitializer를 사용하는 게 편하고 간단하다는 것을 알 수 있습니다.

XML방식

<?xml version="1.0" encoding="UTF-8"?>

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  
  <!-- listener를 선언해줍니다. -->
  <!-- context가 로딩될  이부분을 읽어서 수행하게 됩니다. -->
  <listener>
  	<listener-class>
  		org.springframework.web.context.ContextLoaderListener
  	</listener-class>
  </listener>
  
  <!-- listener가 실행될  context-param에 등록되어 있는 것들을 참고하게 됩니다. -->
  
  <!-- listener에서 java Configuration을 이용하려면 이부분이  필요합니다!! -->
  <context-param>
  	<param-name>contextClass</param-name>
  	<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  
  <!-- 공통으로 사용할 Config 파일을 가져옵니다. -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>kr.or.connect.mvcguestbook.config.ApplicationConfig</param-value>
  </context-param>
  
  	  
   <servlet>
    <servlet-name>mvc</servlet-name>
    <!-- Spring이 제공하고 있는 DispatcherServlet을 FrontController로  것이라는 <servlet-class> 등록되어 있습니다. -->
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextClass</param-name>
      <!-- DispatcherServlet이 실행될  AnnotationConfigWebApplicationContext를 사용하기 위해 등록되어 있습니다. -->
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <!-- DispatcherServlet이 실행될  설정들을 읽어야 하기 때문에 -->
      <!-- <init-param>부분에 우리가 만든 WebMvcContextConfiguration를 설정하고 있는 것을   있습니다. -->
      <param-value>kr.or.connect.mvcguestbook.config.WebMvcContextConfiguration</param-value>
    </init-param>    
    <!-- 프로그램 시작과 동시에 서블릿의 생성과 초기화를 진행할  사용합니다. -->
    <!-- 여러 서블릿들간에 우선순위가 필요한 경우 0 가까울수록 먼저 초기화가 진행됩니다. -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/</url-pattern>
    <!-- "/"요청이 들어오면 <servlet>안에 있는 <servlet-name> "mvc" 이름을 찾아갑니다. -->
  </servlet-mapping>
  
  
  <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
</filter>
<filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <!--  필터의 적용범위를 설정해줍니다. "/*" 모든 범위, 특정 URL에만 지정할 수도 있습니다. -->
        <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 데이터를 주고 받을  한글이 제대로 나오게 해줍니다. -->
  
  
</web-app>

WebApplicationInitializer

public class WebApplicationInitializer implements WebApplicationInitializer  {
		// 웹 어플리케이션이 시작할 때 자동으로 이 메서드가 실행 됩니다.
	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		registerListener(servletContext);
		registerDispatcherServlet(servletContext);
		registerFilter(servletContext);
	}
	
	// 리스너를 생성하는 함수입니다. Override된 onStartup() 함수에서 호출해야 합니다.
	private void registerListener(ServletContext servletContext) {
		// ApplicationConfig(java Configuration)를 이용해 AnnotationConfigWebApplicationContext을 만들고 
		AnnotationConfigWebApplicationContext context = createContext(ApplicationConfig.class);
        // Listener에 context-param을 등록해 줍니다.
		servletContext.addListener(new ContextLoaderListener(context));
	}
	
	// DispatcherServlet를 만들어 줍니다.
	private void registerDispatcherServlet(ServletContext servletContext) {
        // WebMvcContextConfiguration(java Configuration)를 이용해 AnnotationConfigWebApplicationContext을 만들고
		AnnotationConfigWebApplicationContext context = createContext(WebMvcContextConfiguration.class);
		
        // DispatcherServlet를 만든 후, 서블릿들 간의 우선순위를 정해주고, url-pattern을 지정해줍니다.
		ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
		dispatcher.setLoadOnStartup(1);
		dispatcher.addMapping("/");
	}
	
	// 필터를 만듭니다.
	private void registerFilter(ServletContext servletContext) {
		// CharacterEncodingFilter 인자의 true, true는 request, response이 존재할 때 encoding을 적용한다는 것입니다. 
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter("UTF-8", true, true);
		FilterRegistration.Dynamic webEncodingFilter = servletContext.addFilter("webEncodingFilter", encodingFilter);
		webEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
	}
	
	// 필터를 만듭니다.
	private void registerFilter(ServletContext servletContext) {
      // CharacterEncodingFilter 인자의 true, true는 request, response이 존재할 때 encoding을 적용한다는 것입니다.
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter("UTF-8", true, true);
		FilterRegistration.Dynamic webEncodingFilter = servletContext.addFilter("webEncodingFilter", encodingFilter);
		webEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
	}
}

AbstractAnnotationConfigDispatcherServletInitializer

public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
        // 배열로 되어있기 때문에 ','로 여러개의 Config파일을 지정할 수 있습니다.
		return new Class<?>[] {ApplicationConfig.class};
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class<?>[] {WebMvcContextConfiguration.class};
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] {"/"};
	}
	
	@Override
	protected Filter[] getServletFilters() {
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        // request와 response에 encoding을 적용한다는 것입니다.
        encodingFilter.setForceEncoding(true);

        return new Filter[]{encodingFilter};
	}

참고 : https://hashmap27.tistory.com/6

https://joont92.github.io/spring/WebApplicationInitializer/

댓글남기기