포스트

Day92 java프로그래밍 기초(Spring web MVC)

Spring web MVC

1. Servlet 등록

1) Servlet Contatiner가 시작될 때 보고 받는 객체

1) 서블릿 컨테이너를 시작한다. 2) 서블릿 컨테이너는 /WEB-INF/lib/*.jar 파일을 뒤진다. 3) /META-INF/services/javax.servlet.SerlvetContainerInitializer 파일을 찾는다. 4) 그 파일에서 ServletContainerInitializer 구현체를 알아낸다. 5) 해당 구현체의 인스턴스를 생성한 후 onStartup()을 호출한다. 6) 만약 그 구현체가 보고 받고자 하는 타입이 있다면 해당 클래스를 찾아 onStartup()을 호출할 때 파라미터로 넘겨준다. image

2) WebApplicationInitializer로 Servlet 등록하기

1) 서블릿 컨테이너(예: 톰캣 서버)를 시작한다. 2) spring-web-*.jar 파일에서 /META-INF/service/javax.servlet.SerlvetContainerInitializer 파일을 읽는다. 3) 이 파일에 등록된 클래스의 인스턴스를 생성한다. => SpringServletContainerInitializer 인스턴스 생성 4) SpringServletContainerInitializer 객체에 대해 onStartup()을 호출한다. => 호출할 때 WebApplicationInitializer를 구현한 클래스 목록을 넘겨준다. 5) SpringServletContainerInitializer는 WebApplicationInitializer 구현체의 인스턴스를 만들고, onStartup()을 호출한다. image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   public class WebApplicationInitializerImpl implements WebApplicationInitializer {
   
     @Override
     public void onStartup(ServletContext servletContext) throws ServletException {
       System.out.println("WebApplicationInitializerImpl.onStartup()...호출됨!");
   
       // DispatcherServlet 에서 사용할 스프링 IoC 컨테이너를 준비한다.
       AnnotationConfigWebApplicationContext iocContainer =
           new AnnotationConfigWebApplicationContext();
   
       // => IoC 컨테이너의 설정 정보를 갖고 있는 Java Config 클래스를 직접 지정하기
       iocContainer.register(AppConfig.class);
   
       // => Java Config 클래스가 있는 패키지를 지정하기
       //    단 이럴 경우 Java Config 클래스에는 @Configuration 애노테이션이 선언되어 있어야 한다.
       // iocContainer.scan("bitcamp");
   
       iocContainer.refresh();
   
       // DispatcherServlet 인스턴스를 생성한다.
       DispatcherServlet servlet = new DispatcherServlet(iocContainer);
   
       // 웹 애플리케이션에 DispatcherServlet을 등록한다.
       Dynamic registration = servletContext.addServlet("app", servlet);
   
       // 웹 애플리케이션에 등록된 DispatcherServlet을 설정한다.
       registration.setLoadOnStartup(1);
   
       // DispatcherServlet에 URL 패턴을 지정한다.
       registration.addMapping("/app/*");
     }
   }

3) AbstractContextLoaderInitializer로 Servlet 등록하기

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class WebInit3 extends AbstractContextLoaderInitializer {
  @Override
  protected WebApplicationContext createRootApplicationContext() {
    // ContextLoaderListener가 사용할 IoC 컨테이너를 리턴한다.
    // 만약 IoC 컨테이너를 리턴하지
    // ContextLoaderListener는 생성하지 않는다.
    return null;
  }
  @Override
  public void onStartup(ServletContext ctx) throws ServletException {
    System.out.println("WebInit2.onStartup() 호출됨!");
    /*
    // 기존의 onStartup() 메서드의 기능은 그대로 수행한다.
    super.onStartup(ctx);
    // DispatcherServlet의 IoC 컨테이너 생성
    AnnotationConfigWebApplicationContext iocContainer =
        new AnnotationConfigWebApplicationContext();
    iocContainer.setServletContext(ctx);
    iocContainer.register(bitcamp.AppConfig.class);
    // DispatcherServlet 객체 생성
    DispatcherServlet frontController = new DispatcherServlet(iocContainer);
    // 서블릿 컨테이너에 등록
    Dynamic options = ctx.addServlet("app", frontController);
    // 서블릿 설정
    options.addMapping("/app/*");
     */
  }
}

4) AbstractDispatcherServletInitializer로 Servlet 등록하기

  • AbstractDispatcherServletInitializer 클래스에서 먼저 DispatcherServlet 객체를 생성하여 등록했다. 1) ContextLoaderListener 가 사용할 IoC 컨테이너를 설정한다. => createRootApplicationContext() 메서드 오버라이딩 2) DispatcherServlet이 사용할 IoC 컨테이너를 설정한다. => createServletApplicationContext() 메서드 오버라이딩 3) DispatcherServlet에 적용할 URL 매핑을 설정한다. => getServletMappings() 메서드 오버라이딩 image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
     public class WebApplicationInitializerImpl
     extends AbstractDispatcherServletInitializer {  
       @Override
       protected WebApplicationContext createRootApplicationContext() {
         // ContextLoaderListener 가 사용할 IoC 컨테이너를 리턴한다.
         // 만약 null을 리턴한다면,
         // 스프링 WebMVC 프레임워크는 ContextLoaderListener를 생성하지 않을 것이다.
         return null;
       }
       
       @Override
       protected WebApplicationContext createServletApplicationContext() {
         // DispatcherServlet이 사용할 IoC 컨테이너를 리턴한다.
         // 스프링 WebMVC 프레임워크는 DispatcherServlet을 만들 때
         // 이 메서드가 리턴한 IoC 컨테이너를 DispatcherServlet에 주입할 것이다.
       
         //1) XML 기반 IoC 컨테이너를 사용할 경우,
         //    XmlWebApplicationContext iocContainer = new XmlWebApplicationContext();
         //    iocContainer.setConfigLocation("/WEB-INF/app-servlet.xml");
       
         //2) Java Config 기반 IoC 컨테이너를 사용할 경우,
         AnnotationConfigWebApplicationContext iocContainer =
             new AnnotationConfigWebApplicationContext();
         iocContainer.register(AppConfig.class);
         return iocContainer;
       }
       
       @Override
       protected String[] getServletMappings() {
         return new String[] {"/app/*"};
       }
       
       @Override
       protected String getServletName() {
         return "app";
       }
       
       @Override
       public void onStartup(ServletContext servletContext) throws ServletException {
         // 이 메서드가 호출될 때 간단한 메시지를 출력하기 위해 오버라이딩 하였다.
         // 따라서 원래의 메서드를 반드시 호출해줘야 한다.
         System.out.println("WebApplicationInitializerImpl.onStartup()...호출됨!");
         super.onStartup(servletContext);
       }
     }
    

5) AbstractAnnotationConfigDispatcherServletInitializer로 Servlet 등록하기

  • 인터페이스를 직접 구현하는 대신에 그 인터페이스를 미리 구현한 AbstractAnnotationConfigDispatcherServletInitializer 클래스를 상속 받기
  • IoC 컨테이너를 따로 설정할 필요가 없다.
  • DispatcherServlet을 등록하는 코드가 이미 작성되어 있기 때문에 따로 등록할 필요가 없다.

    image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
      public class WebApplicationInitializerImpl
      extends AbstractAnnotationConfigDispatcherServletInitializer {
        
        @Override
        protected Class<?>[] getRootConfigClasses() {
          System.out.println("==> getRootConfigClasses()");
          // ContextLoaderListener의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다.
          return null;
        }
        
        @Override
        protected Class<?>[] getServletConfigClasses() {
          System.out.println("==> getServletConfigClasses()");
          // DispatcherServlet의 IoC 컨테이너가 사용할 Java config 클래스를 리턴한다.
          return new Class<?>[] {AppConfig.class};
        }
        
        @Override
        protected String[] getServletMappings() {
          System.out.println("==> getServletMappings()");
          // DispatcherServlet을 등록할 때 이 메서드를 호출한다.
          // 이 메서드의 리턴 값이 리턴 값이 URL 패턴으로 사용된다.
          return new String[] {"/app/*"};
        }
        
        @Override
        protected String getServletName() {
          System.out.println("==> getServletName()");
          // DispatcherServlet을 등록할 때 이 메서드를 호출한다.
          // 이 메서드의 리턴 값이 서블릿의 이름으로 사용된다.
          // 이 메서드를 오버라이딩 하지 않으면 기본 이름("dispatcher")이 사용된다.
          // => 한 개만 등록할 것이라면 오버라이딩 하지 않아도 되지만,
          //    여러 개의 DispatcherServlet을 등록할 것이라면 오버라이딩 하여
          //    반드시 이름을 다르게 해야 한다.
          return "app";
        }
        
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
          // 이 메서드가 호출될 때 간단한 메시지를 출력하기 위해 오버라이딩 하였다.
          // 따라서 원래의 메서드를 반드시 호출해줘야 한다.
          System.out.println("WebApplicationInitializerImpl.onStartup()...호출됨2!");
          super.onStartup(servletContext);
        }
      }
    

6) 1 ContextLoaderListener & 2 DispatcherServlet 설정하기

  • ContextLoaderListener는 Servlet Container에서 공용으로 사용하기 때문에 하나의 Servlet에서 getRootConfigClasses을 설정한다. image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    
      public class AppDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
        
        @Override
        protected Class<?>[] getRootConfigClasses() {
          // ContextLoaderListener 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다.
          return new Class<?>[] {RootConfig.class};
        }
        
        @Override
        protected Class<?>[] getServletConfigClasses() {
          // DispatcherServlet 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다.
          return new Class<?>[] {AppConfig.class};
        }
        
        @Override
        protected String[] getServletMappings() {
          return new String[] {"/app/*"};
        }
        
        @Override
        protected String getServletName() {
          return "app";
        }
      }
        
      //RootConfig
      @ComponentScan(
          value="bitcamp",
          excludeFilters = {
              @Filter(type = FilterType.REGEX, pattern = "bitcamp.web.*")
          })
      public class RootConfig {
      }
        
      //AppConfig
      @ComponentScan("bitcamp.web.app")
      public class AppConfig {
      }
        
      //Admin
      public class AdminDispatcherServletInitializer  extends AbstractAnnotationConfigDispatcherServletInitializer {
        @Override
        protected Class<?>[] getRootConfigClasses() {
          // ContextLoaderListener 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다.
          // AppDispatcherServletInitializer 에서 이미 설정했기 때문에
          // 여기서는 null을 리턴한다.
          return null;
        }
        
        @Override
        protected Class<?>[] getServletConfigClasses() {
          // DispatcherServlet 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다.
          return new Class<?>[] {AdminConfig.class};
        }
        @Override
        protected String[] getServletMappings() {
          return new String[] {"/admin/*"};
        }
        
        @Override
        protected String getServletName() {
          return "admin";
        }
      }
        
      //AdminConfig
      @ComponentScan("bitcamp.web.admin")
      public class AdminConfig {
      }
    
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.