til icon indicating copy to clipboard operation
til copied to clipboard

Root, Servlet WebApplicationContext

Open raycon opened this issue 2 years ago • 1 comments

DispatcherServlet

  • Root WebApplicationContext
    • Servlet 에 의해 생성
  • Servlet WebApplicationContext
    • DispatcherServlet 에 의해 생성
  • Servlet WebApplicationContext 에서 빈을 조회할 수 없는 경우 Root WebApplicationContext를 조회

web.xml 로 정의

<web-app>

    <!-- Root -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>

    <!-- Servlet -->
    <servlet>
        <servlet-name>app1</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/app1-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app1</servlet-name>
        <url-pattern>/app1/*</url-pattern>
    </servlet-mapping>

</web-app>

Java 로 정의:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // Root
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }

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

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

web.xml 대신 자바 정의를 사용할 수 있는 이유

  • 서블릿 컨테이너가 초기화 될 때 spring-web 에서 정의한 org.springframework.web.SpringServletContainerInitializer 가 실행된다.
    • javax.servlet.ServletContainerInitializer 를 구현
    • @HandleTypes 값으로 org.springframework.web.WebApplicationInitializer 를 지정
    • 서블릿이 클래스패스에 존재하는 org.springframework.web.WebApplicationInitializer의 구현체를 스캔해서 onStartup 메소드의 파라미터로 전달
  • AbstractAnnotationConfigDispatcherServletInitializerorg.springframework.web.WebApplicationInitializer 를 구현
  • org.springframework.web.SpringServletContainerInitializer 가 여러개의 org.springframework.web.WebApplicationInitializer 를 호출하는 방식으로 작동한다.
  • 서블릿 컨테이너에 war를 배포할 경우 사용되는 시나리오

스프링 부트에서 컨텍스트가 초기화되는 방법

  • 스프링 부트는 Embedded Tomcat 을 사용하기 때문에 위 시나리오와는 다른 방식으로 스프링 컨테이너가 초기화된다.
  • 스프링 컨테이너가 초기화 된 뒤 내장 톰캣이 실행된다.
  • org.springframework.web.SpringServletContainerInitializer 대신 org.springframework.boot.web.servlet.ServletContextInitializer 를 구현하는 빈을 등록한다.
  • 스프링 부트에서는 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext를 사용한다.
    • createWebServer() 에서 웹 서버를 생성하고
    • org.springframework.boot.web.servlet.ServletContextInitializer 를 찾아서 서블릿 컨텍스트를 초기화하는데 사용한다.
    • org.springframework.boot.web.servlet 패키지에 있는 ~RegistrationBeanorg.springframework.boot.web.servlet.ServletContextInitializer를 상속받는다.
    • ServletRegistrationBean, FilterRegistrationBean, ServletListenerRegistrationBean 을 사용해서 서블릿 컨테이너를 초기화 할 수 있다.

Root WebApplicationContext 와 Servlet WebApplicationContext 가 연결되는 지점:

  • DispatcherServletFrameworkServlet을 상속 받는다
  • AnnotationConfigApplicationContextGenericApplicationContext를 상속받는다.
  • WebApplicationInitializer 를 구현한 WebApplicationInitializerregisterDispatcherServlet(ServletContext servletContext) 메소드에서 DispatcherServlet 을 생성한다.
  • javax.servlet.GenericServletinit(ServletConfig config) 메소드가 실행된다
  • org.springframework.web.servlet.HttpServletBeaninit() 메소드가 실행된다.
  • org.springframework.web.servlet.FrameworkServlet
    • initServletBean() 메소드가 실행된다.
    • initWebApplicationContext() 메소드가 실행된다.
      • 서블릿 컨텍스트에서 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 로 등록된 attribute 를 조회한다. -> Root Context
      • DispatcherServlet에 생성된 WebApplicationContext 객체의 setParent() 메소드를 호출해서 Root Context 와 연결한다.

raycon avatar Sep 30 '22 02:09 raycon

Servlet Context Initialization

  • https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#web.servlet.embedded-container.context-initializer

Context Hierarchy

  • https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet-context-hierarchy

raycon avatar Sep 30 '22 04:09 raycon