WebApplicationContext란?큰 흐름(Spring Boot 시동시)ServletContextWebApplicationInitializer <interface>ContextLoaderListener → ServletContextListener(interface) : root WebApplicationContext생성Root WebApplicationContext와 Servlet application Context에 대한 추가 설명구동 원리(클라이언트 요청부터)Layer 구분(presentation layer -Spring MVC, service layer, data access layer)
WebApplicationContext란?
- ApplicationContext를 상속받고 있음. ApplicationContext와의 차이점은 servlet에 접근할 수 있냐 없냐의 차이
- Servlet Context에 접근할 수 있는 기능이 추가된 ApplicationContext임
- ServletContext는 ServletContainer에 의해 만들어지는 객체
큰 흐름(Spring Boot 시동시)
- (생성 — initiation)WAS(Tomcat)에 의해 서블릿 컨테이너가 구동됨
- (생성 — initiation)서블릿 컨테이너에 서블릿 컨텍스트가 생성이 됨
- ApplicationContext <class> —(구현)→ ServletContext <interface>
//StandardContext 클래스 public ServletContext getServletContext() { if (this.context == null) { this.context = new ApplicationContext(this); if (this.altDDName != null) { this.context.setAttribute("org.apache.catalina.deploy.alt_dd", this.altDDName); } } return this.context.getFacade(); }
- (생성) ServletWebServerApplicationContext.selfInitialize() 에서 WebApplicationContext 생성
- (초기화 — initialization) 서블릿 컨텍스트에 추가적인 filter, servlet, listener들을 초기화함( 서블릿 컨테이너가 init() 메서드 호출함으로써)
ServletContext

- 서블릿 컨테이너에 의해 생성되는 주요 서블릿이 있고, 해당 서블릿의 서블릿 컨텍스트에 추가적인 서블릿들을 등록하여 초기화 할 수 있는데, 이 때 이렇게 생성된 서블릿들 사이에서 공유할 수 있는 부분이 ServletContext임
WebApplicationInitializer <interface>
// SpringServletContainerIntializer.class public class SpringServletContainerInitializer implements ServletContainerInitializer { public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { // .... 앞 부분 중략 ... // while(var4.hasNext()) { WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next(); initializer.onStartup(servletContext); } }
public class PrgmWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { } }
- 서블릿 컨테이너가 생성될 때 SpringServletContainerInitializer.onStartup()이 호출되고 그 안에서 WebApplicationInitializer.onStartup() 이 호출됨
- WebApplicationInitializer.onStartup() 안에서 ServletContext의 configuration을 추가하고 수정할 수 있음
ContextLoaderListener → ServletContextListener(interface) : root WebApplicationContext생성
- 모든 WebApplicationContext가 접근이 가능한 root WebApplicationContext이 필요함
- 근데 사실 현재는 어차피 서버를 여러 대 따로 두기 때문에 하나의 서버 당 하나의 WebApplicationContext를 주로 쓰게 됨. 어차피 마이크로 서비스로 분리하기 때문에
- 위 처럼 한다는 것은 하나의 서버에 여러 개의 서블릿을 두고 서블릿 사이에 공유하기 위한 컨텍스트 즉 root WebApplicationContext가 필요하다는 이야기
- ServletContext가 생성될 때 Root WebApplicationContext도 생성됨
- ServletContextListeners는 ServletContext가 생성되거나 업데이트될 때 호출됨
@Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext rootApplicationContext = new AnnotationConfigWebApplicationContext(); rootApplicationContext.register(RootConfig.class); var loaderListener = new ContextLoaderListener(rootApplicationContext); servletContext.addListener(loaderListener); AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(ServletConfig.class); var dispatcherServlet = new DispatcherServlet(applicationContext); var servletRegistratrion = servletContext.addServlet("test", dispatcherServlet); servletRegistratrion.addMapping("/"); servletRegistratrion.setLoadOnStartup(1); }

Root WebApplicationContext와 Servlet application Context에 대한 추가 설명


- DispatcherServlet은 여러개가 만들어질 수 있고 Controller는 해당 DispatcherServlet에 매핑되어 있고
- DispatcherServlet에서 사용하는 Controller는 DispatcherServlet을 만들 때 전달한 WebApplicationContext 즉, Servlet ApplicationContext라고 부르는 Ioc컨테이너가 생기는 것임. 여기에 Controller등록, DispatcherServlet이 필요한 빈들이 다 등록이 됨(어댑터 핸들러 리솔버 등등)
- root ApplicationContext는 하나만 만들어지고, 여러 Servlet에서 공통으로 접근하는 영역임. 얘에 대해 자식인 servletApplicationContext가 쭉쭉 만들어지는 것
- 하나를 통으로 만들 수도 있음. servlet이 하나만 만들고 끝나면. 여기에 컨테이너의 모든 빈들을 등록하는 것
- 예전에는 하나의 Application에 다 등록했었음 monolithic 구조. 수직적 확장(램 끼우고.. 등등 서버 성능을 계속 업그레이드 하는 것)
- 그러나 마이크로 서비스 아키텍처로 하면서 service를 여러 application으로 나눠서 처리하면서 수평적 확장. 하나의 서버가 하나의 기능만 담당. 결제, 주문, 바우처 관리 서비스 따로 따로. 테크 스텍을 아예 다 분리를 시키는 것
- 예전에 monolithic 구조일 때 service가 1000개, controller가 1500개 이럴 때, rootApplicationContext 하나에 servletApplicationContext를 여러개 붙여서 loadOnStartup 옵션 넣어서 사용많이 했음. 그렇게 하면 처음에는 rootApplicationContext만 뜨고 request가 들어올 때마다 해당하는 servletApplicationContext를 구동시켜서 모든 Controller를 한번에 띄우는 것이 아닌 필요할 때만 띄우도록 구성을 하는 것. 처음에 서버 띄울 때 빠르게 띄울 수 있음. 나중에는 결국 다 뜨게 되겠지만
- 요즘에는 아예 서버(컨테이너) 자체를 다 나눠버리는 방식을 택함
구동 원리(클라이언트 요청부터)

- 웹 어플리케이션에서 WebApplicationContext를 생성을 하고 DispatcherServlet이 요청을 받으면 WebApplicationContext에서 등록되어 있는 빈을 가지고 옴
- POJO 빈 오브젝트 — 관련되어 있는 Handler, Adapter들
- ApplicationContext.xml , xml → 자바 코드로 가능함
Layer 구분(presentation layer -Spring MVC, service layer, data access layer)

- AOP는 전반적으로 다쓰게 되고, Model도 프레젠테이션, 서비스 데이터 액세스 쪽 다 쓰게 되고
- DTO는 요청, 응답쪽에서 쓰게 되고
- JDBC Template은 데이터 액세스 계층
- WAS 전체는 전부다 Spring Container의 IoC가 적용이 됨