[Spring 3.1] 스프링 MVC와 웹 기술 - 핸들러
스프링은 웹 기술에서 독립적인 루트 애플리케이션 컨텍스트와 웹 기술 기반으로 동작하는 서블릿 애플리케이션 컨텍스트 두 가지로 애플리케이션 컨텍스트를 분리해서 구성한다. (계층 구조로 구성돼 서블릿 애플리케이션 컨텍스트는 루트 애플리케이션 컨텍스트에 접근할 수 있다)
루트 애플리케이션 컨텍스트에서는 서비스, 리포지토리 등 웹과 관련된 기능을 제외한 모든 빈을 관리하고,
서블릿 애플리케이션 컨텍스트에서는 핸들러 매핑, 뷰 리졸버 등 웹과 관련된 빈들을 관리한다.
배치 작업 등 웹과 관련되지 않은 애플리케이션은 웹 관련 빈들을 관리하는 서블릿 애플리케이션 컨텍스트가 필요하지 않다.
이렇게 애플리케이션을 두 개로 분리하면 서블릿 애플리케이션 컨텍스트를 다른 기술로 교체하거나 제거할 수 있어 애플리케이션을 효과적으로 관리할 수 있다.
스프링 프레임워크는 유연성과 확장성에 무게를 두고 있고, 이런 확장성을 최대한 활용해서 프로젝트에 최적화된 구조를 적용해보자.
스프링 웹 기술은 MVC 아키텍처를 기본으로 하고, MVC 아키텍처는 프론트 컨트롤러 역할을 수행하는 디스패처 서블릿을 핵심 엔진으로 사용하고 있다.
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
web.xml에서 디스패처 서블릿을 선언한다.
URL이 /로 시작하는 모든 HTTP 요청을 디스패처 서블릿으로 할당하고, 디스패처 서블릿의 이름은 appServlet으로 설정한다.
디스패처 서블릿은 받은 요청에 대해 전처리 작업 (보안, 인코딩 등) 이 있다면 수행하고 핸들러 매핑 전략을 사용해 어떤 컨트롤러에 작업을 위임할 지 결정한다. (요청을 기준으로 작업을 위임하는 전략이다)
핸들러 매핑 전략은 DI를 통해 확장할 수 있으니 어떤 URL에 대해 어떤 컨트롤러 오브젝트가 요청을 처리할 지 자기 입맛대로 정의할 수도 있다.
디스패처 서블릿이 컨트롤러의 메서드를 호출할 때는 어댑터를 사용한다.
디스패처 서블릿이 컨트롤러의 정보를 알 필요는 없다.
대신, 컨트롤러의 종류에 따라 적절한 어댑터를 사용해 어댑터가 컨트롤러에 해당하는 호출 방법을 사용해 요청을 보내고 응답받는 방식을 사용한다. (웹 요청 전달에는 HttpServletRequest, HttpServletResponse 오브젝트가 사용된다)
이를 핸들러 어댑터 전략이라고 부르고, 역시 DI를 통해 확장할 수 있다.
컨트롤러는 클라이언트의 요청을 해석하고, 서비스 계층을 호출해 비즈니스 로직을 처리하고 결과를 모델에 넣고 결과를 보여줄 뷰를 모델과 함께 디스패처 서블릿에게 전달하는 역할을 수행한다. (뷰는 JSP, 엑셀 등 여러 가지가 될 수 있다)
모델과 뷰를 받은 디스패처 서블릿은 모델을 뷰에 전달하고 뷰는 결과물을 렌더링 후 HttpServletReponse 오브젝트에 다아 디스패처 서블릿에게 전달한다.
뷰가 생성됐으면 디스패처 서블릿은 후처리기가 있다면 후처리 작업을 수행하고 서블릿 컨테이너에게 뷰로부터 전달받은 오브젝트를 돌려준다.
서블릿 컨테이너는 HttpServletResponse에 담긴 정보를 HTTP 응답으로 만들어 클라이언트에게 전송하고 작업을 종료한다.
여기까지가 클라이언트의 요청이 들어왔을 때 스프링이 요청을 처리하는 과정이다.
이 중에서 컨트롤러는 MVC 세 가지 컴포넌트 중에서 가장 많은 책임을 지고 있다.
서블릿이 넘기는 HTTP 요청은 HttpServletRequest 오브젝트로 전달되고, 이 객체에는 세션, 쿠키, 헤더, URI, 호스트, 포트 등 다양한 정보를 포함한다.
컨트롤러는 필요한 정보를 추출하고 클라이언트가 제대로 요청했는지도 다양한 조건을 사용해 검증한다.
클라이언트의 요청을 모두 분석했으면 서비스 계층을 호출해 비즈니스 로직을 처리하고, 결과를 반환받으면 어떤 뷰를 보여줘야 하는지 결정한다.
스프링 MVC의 디스패처 서블릿은 핸들러 어댑터를 사용해 컨트롤러를 연결하고, 핸들러 어댑터마다 컨트롤러가 하나씩 매핑된다. (종류)
1. Servlet / SimpleServletHandlerAdapter
표준 서블릿을 컨트롤러로 사용하고, 서블릿에 해당하는 핸들러 어댑터를 사용한다.
잘 사용하지는 않는다.
2. HttpRequestHandler / HttpRequestHandlerAdapter
HTTP 프로토콜을 기반으로 하는 서비스를 만들 때 사용한다.
모델과 뷰 개념이 없는 로우레벨 서비스 개발 시 활용된다.
3. Controller / SimpleControllerHandlerAdapter
@Controller를 사용하기 전에 많이 사용되던 컨트롤러였다.
Controller 인터페이스를 구현한 AbstractController 클래스를 상속해서 구현하는게 일반적이다.
AbstractController 클래스는 synchronizeOnSession, supportedMethods 등을 사용해 세션에 접근하거나 컨트롤러가 허용하는 HTTP 메서드를 지정하는 등 여러 작업을 처리할 수 있다.
public abstract class SimpleController implements Controller {
private String[] requreidParam;
private String viewName;
public void setParams(String[] a) {
this.requreidParam = a;
}
public void setViewname(String b) {
this.viewName = b;
}
final public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
}
....
}
대충 위와 같은 방식으로 사용한다.
컨트롤러는 URL 하나와 매핑된다.
4. AnnotationMethodHandlerAdapter
해당 어댑터는 지원하는 컨트롤러의 타입이 정해져 있지 않고, 클래스와 메서드의 정보를 바탕으로 컨트롤러를 선별하고 호출 방식을 결정한다.
다른 컨트롤러와는 다르게 컨트롤러 하나가 하나 이상의 URL에 매핑될 수 있고, URL의 매핑을 메서드 단위로 수행한다. (이전까지는 컨트롤러 단위로 수행했다)
스프링 MVC의 초기 버전에서 애너테이션 기반 컨트롤러 (@Controller) 를 지원하기 위해 사용됐지만 3.1 이후로는 RequestMappingHandlerAdapter가 사용된다.
핸들러 매핑은 클라이언트의 요청을 어떤 컨트롤러에게 위임할지를 결정하는 디스패처 서블릿의 전략이고,
핸들러 어댑터는 핸들러 매핑이 찾아낸 컨트롤러를 실제로 실행하는 역할을 수행한다.
이제 핸들러 매핑에 대해 살펴보자.
1. BeanNameUrlHandlerMapping
디폴트 핸들러 매핑 중 하나로, 빈의 이름에 있는 URL을 요청의 URL과 비교해서 빈을 찾는다.
<bean name="/**" class="..Controller">
이런 식으로 컨트롤러 빈이 등록되어있다면 name에 지정된 표현식에 해당하는 URL을 해당 컨트롤러가 받아서 처리한다.
2. ControllerBeanNameHandlerMapping
빈의 아이디나 이름으로 매핑하는 전략이다.
3. ControllerClassNameHandlerMapping
클래스 이름을 URL에 매핑하는 전략이다.
4. SimpleUrlHandlerMapping
빈 정보에 매핑정보를 추가하는 대신 URL과 컨트롤러의 매핑정보를 한 번에 관리하는 전략이다.
프로퍼티 기반 키-값을 사용해 관리한다.
5. DefaultAnnotationHandlerMapping
@RequestMapping 애너테이션을 클래스와 메서드에 부여하고 이를 통해 매핑하는 전략이다.
메서드 단위로 URL을 매핑할 수 있어 컨트롤러의 개수를 줄일 수 있고, HTTP 메서드도 구분할 수 있다.
요청을 컨트롤러로 매핑하고 컨트롤러를 실행하기 전에 디스패처 서블릿은 핸들러 인터셉터를 통해 요청과 응답을 조작할 수 있다.
핸들러 매핑은 디스패처 서블릿으로부터 매핑 작업을 요청받으면 핸들러 실행 체인을 반환하고, 핸들러 실행 체인은 하나 이상의 핸들러 인터셉터를 거쳐서 컨트롤러가 실행될 수 있도록 구성돼있다.
preHandle, postHandle, afterCompletion 메서드를 제공해 컨트롤러가 호출되기 전, 후와 뷰가 생성된 후에 실행되는 작업을 지정할 수 있다.
서블릿 필터와 핸들러 인터셉터가 같은 역할을 하는 것 처럼 보이지만, 서블릿 필터는 서블릿 컨테이너가 관리하고 인코딩 / 보안 / 로깅 등 애플리케이션 전반에 걸친 작업을 수행할 때 사용되고 핸들러 인터셉터는 세션 체크 / 모델 객체 추가 등 컨트롤러 호출 전후에 추가적인 작업을 수행할 때 사용된다. (서블릿 필터는 web.xml에 설정한다)
즉, 작업의 범위와 처리되는 시점에서 차이가 있다.
서블릿 필터는 모든 요청에 대해 처리되고, 디스패처 서블릿에 도달하기 전에 수행되지만 핸들러 인터셉터는 특정 요청에 대해서만 처리되며 디스패처 서블릿을 호출하기 전후에 수행된다.
'Spring > Spring 3.1' 카테고리의 다른 글
[Spring 3.1] 스프링 MVC 애너테이션 (0) | 2023.06.02 |
---|---|
[Spring 3.1] 데이터 엑세스 기술 (0) | 2023.05.11 |
[Spring 3.1] IoC 컨테이너와 스프링의 동작 원리 (0) | 2023.05.10 |
[Spring 3.1] Annotation (0) | 2023.05.04 |
[Spring 3.1] Aspect Oriented Programming (0) | 2023.04.28 |
댓글
이 글 공유하기
다른 글
-
[Spring 3.1] 스프링 MVC 애너테이션
[Spring 3.1] 스프링 MVC 애너테이션
2023.06.02 -
[Spring 3.1] 데이터 엑세스 기술
[Spring 3.1] 데이터 엑세스 기술
2023.05.11 -
[Spring 3.1] IoC 컨테이너와 스프링의 동작 원리
[Spring 3.1] IoC 컨테이너와 스프링의 동작 원리
2023.05.10 -
[Spring 3.1] Annotation
[Spring 3.1] Annotation
2023.05.04