본문 바로가기

컴퓨터공학/Spring framework 분석

개념> DispatcherServlet과 WebApplicationContext

2. DispatcherServlet 

1) WebApplicationContext

 

 


 

DispatcherServlet는 WebApplicationContext를 갖고 있다. 

DispatcherServlet은 프론트 컨트롤러 서블릿이다. 
서블릿이 초기화 할 때 자신만의 context 를 생성하고 초기화한다. 
여러 개가 만들어질 수 있으며 각각 고유한 WebApplicationContext가 있다.
Context의 갯수는 각 서블렛 인스턴스 당 하나이다.
그리고 Root application context를 찾아서 자신의 부모 context로 등록하여 사용한다. 
여러 개의 WebApplicationContext는 하나의 Root WebApplication Context를 공유한다.

Root WebApplicationContext는 최상단에 위치한 Context이다. 
서비스 계층이나 DAO를포함한 웹 환경 독립적인 빈을 담아둔다. 
서로 다른 서블릿컨텍스트에서 공유하는 빈들을 등록하고 사용할 수 있다.
따라서 Root WebApplication Context 에는 서블렛 모두가 필요한 

repository, Service, business service 관련 빈들이 있다.
이러한 빈들은 상속되고 재정의되고 오버라이드할 수 있다.
어디로? WebApplicationContext로. 

 

Servlet WebApplicationContext
DispatcherServlet이 직접 사용하는 컨트롤러를 표함한 웹 관련 빈을 등록하는데 사용한다.
Controller, View Resolver, HandlerMapping 등이 있다.

 

 


DispatcherServlet은 독자적인 WebApplicationContext를 가지고 있고 동일한 Root WebApplicationContext를 공유한다.
그리고 Servlet WebApplication Context는 Root WebApplicationContext를 상속받아 생성된다. 
Servlet에서 관리되는 Servlet WebApplicationContext(자식)
스프링에서 관리하는 Root WebApplicationContext(부모) 관계를 갖는다. 
두 개의 같은 빈이 있다면 자식이 우선이라서 WebApplicationContext 빈이 사용된다.

 

자식 context에서 원하는 Bean을 찾지 못하면 부모 context에서 탐색하게 되며 

자식 context 는 부모 context bean을 공유하게 된다.

 

이런 계층 구조를 갖는 이유는 전체 애플리케이션에서 웹 기술에 의존적인 부분과 아닌 부분을 구분하기 위해서다. 

이런 구조 덕분에 프레젠테이션 계층은 다른 기술을 도입할 수 있다. 

 

 



프레젠테이션 레이어

레이어는 계층을 의미.
상위 레이어는 하위 레이어를 의식하면 된다. 
레이어1(상위) > 레이어2 > 레이어3(하위)
이렇게 있으면 레이어2가 신경쓸 것은 레이어2인 자기 자신과 레이어3이다. 상위 레이어1은 신경 쓸 필요 없다. 
프레젠테이션 레이어 > 비즈니스 레이어 > 데이터 액세스 레이어 
프레젠테이션 레이어는 시스템 사용자와 인터페이스를 담당하는 레이어
웹 브라우저로 사용자 입력을 받아서 하위 레이어인 비즈니스 로직 레이어에 전달
결과를 다시 웹 브라우저에 표시하거나 화면 이동 제어를 담당

비즈니스레이어 고유 작업을 처리하기 위한 레이어 
데이터 액세스 레이어로 데이터베이스를 이용하여 작업 처리 
결과값을 프레젠테이션 레이어에 반환

데이터 액세스 레이어
비즈니스 로직 레어어와 데이터베이스를 중개하는 레이어
데이터베이스에 연결하려면 코드 작성이 필요
이 처리를 비즈니스 로직에서 분리하여 데이터베이스 연결 절차를 일일이 의식하지 않아도 이용 가능하게 도와준다.

레이어 패턴과 mvc 패턴
웹 애플리케이션 레이어와 mvc 패턴은 상반하지 않다.
컨트롤러와 뷰는 프레젠테이션 레이어
모델은 비즈니스 로직 레이어와 액세스 레이어로 나뉜다. 


model(데이터) view(인터페이스)  controller(데이터와 로직 사이 상호작용을 관리)
mvc는 인터페이스와 비즈니스 로직을 분리하여 서로 영향을 주지 않고
쉽게 고칠 수 있는 애플리케이션을 만들 수 있다. 

 

 

 

그러면 Servlet Context에서 어떻게 Root Application Context에 접근할 수 있는 것인가?
스프링은 외부에서 Root Application Context에 접근할 수 있도록 유틸리티를 제공한다.
외부 Servlet Context는 유틸리티를 이용하여 Root Application Context 에 있는 필요한 빈을 접근할 수 있다.

 

 

 


 


context-param과 init-param의 차이점

servlet 만들어서 사용하는 법?
init-param은 지정해준 servlet에서만 쓸 수 있는 값이다. 

private 지역 변수와 유사하다. ServletConfig 의 getInitParameter 를 이용하여 부를 수 있다.
context-param은 모든 servlet에서 사용할 수 있는 파라미터 값이다.

따라서 어떤 servlet 태그 안에 속하는 것이 아닌 독립적으로 추가한다.  

ServletContext 의 getInitParameter를 이용하여 부를 수 있다. 
spring framework에 dispatcherServlet 클래스가 있지만 커스텀 서블릿 클래스를 만들어서보자.

 

 

InitTestServlet.java

public class InitTestServlet extends HttpServlet{
@Override 
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
	PrintWriter out = resp.getWriter( );
	out.print("email : " + getServletConfig().getInitParameter("email") + "<br/>");
	out.print("addr : " + getServletConfig().getInitParameter("addr") + "<br/>");

	out.print("name : " + getServletContext().getInitParameter("name") + "<br/>");
	out.print("age : " + getServletContext().getInitParameter("age"));
}
}

 

 

web.xml 

<servlet>
	<servlet-name>InitTest</servlet-name>
	<servlet-class>InitTestServlet</servlet-class>
	<init-param>
		<param-name>email</param-name>
		<param-value>seol@seo.com</param-value>
	</init-param>
	<init-param>
		<param-name>addr</parm-name>
		<param-value>busan</param-value>
	</init-param>
	<servlet-mapping>
		<servlet-name>InitTest</servlet-name>
		<url-pattern>/init</url-pattern>
	</servlet-mapping>
</servlet>


<context-param>
	<param-name>name</param-name>
	<param-value>SEol</param-value>
</context-param>
<context-param>
	<param-name>age</param-name>
	<param-value>27</param-value>
</context-param>

 

 

이번에는 Dispatcher servlet과 ContextLoaderListener가 있는 web.xml을 보자

	<display-name> </display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/root-context.xml</param-value>
	</context-param>

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

	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<session-config>
		<session-timeout>20</session-timeout>
	</session-config>

 


DispatcherServlet는 자신만의 Servlet Application Context를 가진다. 
따라서 Init-param 을 사용해서 servlet-context.xml을 설정한다.
동시에 여러 서블릿이 공유하는 Root Application Context은 context-param으로 root-context.xml을 설정한다. 

listener는 이것을 사용한다. 

 

 

하지만 Root Application Context 계층이 필요없고 모두 Servlet Application Context에 등록하고 싶다면?

dispatcher servlet에 모든 context를 넣고 싶다면??

 

<servlet>
	<servlet-name>dispatcherServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-calss>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:/WEB-INF/*Context.xml</param-value>
	</init-param>
</servlet>

 

이렇게 하면 DispatcherServlet 의 context에 빈이 모두 등록.
그러나 확장성을 위해서 Service, Repository 같은 설정은 

ContextLoaderListener 를 통한 Root Application Context에 등록하자.
프레젠테이션 레이어에 대한 스프링 설정은 DispatcherServlet의 Servlet Application Context에 등록. 

 

 

 

 

 

( 레이어란 무엇인가?
https://jamie95.tistory.com/73 )

( Spring Web MVC
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#spring-web )

( Web application context란?
https://unordinarydays.tistory.com/131 )

( spring framework core
https://velog.io/@koseungbin/Spring-Core )

( 서블릿 파라미터
https://remns.tistory.com/8
https://erjuer.tistory.com/20 )