Spring / Servlet

mjdevv·2024년 1월 8일
0

Spring

목록 보기
1/4

서블릿 컨테이너와 스프링 컨테이너의 관계

Spring MVC로 웹 어플리케이션을 만들다 보면 아래와 같은 의문이 생긴다. 스프링은 웹 기술 아닌가..? 우리는 직접 Servlet을 사용하지 않고 Spring 프레임워크를 사용해서 웹어플리케이션을 만들고 있는데, 그러면 Spring을 사용하고 있는 거지, Servlet을 사용해서 개발을 하고 있는 게 아니지 않나? 기초적인 지식이지만, 이 부분에 혼란이 와서 해당 의문을 정리하기 위해 이 문서를 작성하게 되었다.


짧은 Recap

1. 서블릿 컨테이너란?

  • javax.servlet package에 정의된 인터페이스
  • HTTP 프로토콜을 기반으로 한 동적 응답을 생성하기 위해 고안됨.
  • Servlet Container 안에서 life cycle이 관리된다.

각 서블릿은 서블릿 컨테이너 안에서 관리 되며, 서블릿 컨테이너는 아래와 같은 기능을 제공 해준다.

  1. 서블릿 생명주기 관리
  2. 통신 지원
  3. 멀티쓰레드 지원 및 관리

간단하게 서블릿을 담아 놓고 관리하는 통이라고 생각하면 될 것 같다. 웹 서버의 요청을 받아서, 해당 요청에 대한 동적처리를 담당하는 서블릿을 찾아 매핑 해주고, 서블릿의 유통기한이 지나면 버리기도 한다.

2. 스프링 컨테이너란?

  • 스프링 프레임워크의 핵심 컴포넌트.
  • Inversion of Control 컨테이너

아래와 같은 기능을 제공해준다.

  1. POJO 형식으로 작성된 bean들의 생명주기를 관리
  2. bean들 사이에 의존성이 존재하면 알아서 주입해 줌

스프링 컨테이너 또한 빈을 담아 놓고 관리하는 통이다. 근데 이제 빈을 담을 때 의존 관계가 있으면 알아서 맞춰주는 통. 스프링 컨테이너는 BeanFactory 인터페이스를 상속 받은 ApplicationContext 인터페이스로 정의 되어 있다.


그래서 Servlet 컨테이너와 Spring 컨테이너의 관계는?

우선 아래의 web.xml 설정 파일을 보자. WAS가 기동 되면 설정파일인 web.xml을 읽어서 실행 된다.

	<!-- contextConfigLocation는 파라메터로 사용됨 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	<!-- ApplicationContext를 불러오는 listener -->
    <listener>
    	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

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

위의 설정 파일을 보면 org.springframework.web.servlet.DispatcherServlet에서 정의된 DispatcherServlet을 생성하게 된다. 그리고 패키지 명을 보면 org.springframework.web. 스프링에서 만든 DispatcherServlet이다. 여기가 시작점이 된다.

  1. WAS가 기동
  2. 서블렛 컨테이너가 생성
  3. 설정파일인 web.xml을 읽어 들임
  4. ContextLoaderListener가 웹 어플리케이션이 구동 되는 걸 감지하고 root-context.xml에 따라 ApplicationContext (스프링 컨테이너)를 생성.
  5. ApplicationContext가 생성 되면서 개발자가 정의한 스프링 빈들이 스프링 컨테이너에 담기게 됨.
  6. 스프링에서 만든 DispatcherServlet 인스턴스를 생성하며 아래의 생성자를 호출[서블릿 컨테이너와 스프링 컨테이너의 접점 생성!]

//// DispatcherServlet의 생성자 

public DispatcherServlet(WebApplicationContext webApplicationContext) {
		super(webApplicationContext);
		setDispatchOptionsRequest(true);
	}
  1. 서블릿 생명주기에 따라 서블릿은 한 번 도 실행되지 않은 경우 초기화를 수행하게 된다.

//// DispatcherServlet의 onRefresh 메소드 

	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	protected void initStrategies(ApplicationContext context) {
		//코드들..
		initHandlerMappings(context);//핸들러 매핑
		//코드들..
	}
  1. 그 과정에서 클라이언트 요청 url에 대한 스프링 빈 핸들러를 매핑해주기 위해 아래의 메소드 들을 차례대로 호출하게 된다. 함수의 콜 스택은 아래와 같다 [5].

initStrategy()
-> DispatcherServlet의 onRefresh()에서 initStrategy()를 호출
-> FrameworkServlet의 initWebApplicationContext()에서 onRefresh()을 호출
-> FrameworkServlet의 initServletBean()에서 initWebApplicationContext()을 호출
-> HttpServletBean의 init()에서 initServletBean()을 호출
-> tomcat의 Apache.catalina.core.StandardWrapper의 initServlet()에서 init()을 호출


정리

  • 서블릿 컨테이너와 스프링 컨테이너는 스프링 커뮤니티에서 만든 DispatcherServlet의 ApplicationContext 인터페이스를 접점으로 연결.

REFERENCE

[1] https://live-everyday.tistory.com/197
[2] https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html
[3] https://velog.io/@seculoper235/Application-%EB%93%B1%EB%A1%9D-%EA%B3%BC%EC%A0%95-Web-2%ED%8E%B8-a5yuw6uh
[4] https://stackoverflow.com/questions/51686721/when-does-onrefresh-method-of-dispatcherservlet-gets-called
[5] https://appleg1226.tistory.com/31

profile
방구석 언어기술자

0개의 댓글

관련 채용 정보