( 설명 )
부모 클래스
를 따라 가면 결국 HttpServlet을 상속
받아서 사용하는 서블릿
임을 알 수 있다
DispatcherServler
--> FrameworkServler
--> HttpServletBean
--> HttpServlet
스프링 부트
는 DispatcherServlet
을 서블릿으로 자동 등록
하면서 모든 경로
에 대해 매핑
(이렇게 모든경로에 대해 매핑된 다음
우리가 지정
하는 url경로
에 대해 매핑
된다)
서블릿
이 호출
되면 HttpServlet
의 service()
가 호출
--> FrameworkServlet
에서 service()
를 오버라이드
해두었기 때문에 이를 통해서 서블릿이 시작
된다
--> 이를 통해서 DispatcherServlet.doDispatch()
가 호출
되며 우리의 비즈니스 로직
이 시작
(결국 스프링 MVC의 핵심 동작
은 DispatcherServlet.doDispatch()
에 모두 기술
)
( DispatcherServlet.doDispatch() )
DispatcherServlet.doDisaptch()
핵심 동작 코드
(예외처리
/ 인터셉터 기능
은 제외
한 간단한 로직
만 정리)
protected void doDispatch(HttpServletRequest request, HttpServletResponseresponse) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
processDispatchResult(processedRequest, response, mappedHandler, mv,dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
render(mv, request, response);
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}
- 동작 순서
- 핸들러 조회 :
핸들러 매핑
을 통해 요청 URL
에 매핑된 핸들러(컨트롤러)를 조회
- 핸들러 어댑터 조회 :
핸들러
를 실행할 수 있는 핸들러 어댑터
조회
- 핸들러 어댑터 실행 :
핸들러 어댑터
를 통해 실제 핸들러
를 호출
해서 실행
- ModelAndView 반환 :
핸들러 어댑터
는 핸들러가 반환하는 정보
를 ModelAndView로 변환
해서 반환
- viewResolver 호출 & 실행 :
뷰 리졸버
를 찾고 실행해서 view 반환
- 뷰 렌더링
( 인터페이스 )
- 인터페이스 살펴보기
- 지금까지 설명한 대부분을 확장 가능한
인터페이스로 제공
한다
스프링 MVC의 강점
은 DispatcherServlet
코드 변경 없이 원하는 기능
을 변경
하거나 확장
가능한 것
인터페이스만 구현
해서 DispatcherServlet
에 등록
하면 나만의 컨트롤러
를 만들 수도 있다
(만들일은 거의 없음)
- 주요 인터페이스
- 핸들러 매핑 :
org.springframework.web.servlet.HandlerMapping
- 핸들러 어댑터 :
org.springframework.web.servlet.HandlerAdapter
- 뷰 리졸버 :
org.springframerwork.web.servlet.viewResolver
- 뷰 :
org.springframerwork.web.servlet.View
( 정리 )
스프링 MVC
는 복잡
해서 내부 핵심 구조
만 잘 알고 있어도 충분
--> 직접 기능을 확장
하거나 나만의 컨트롤러를 만들 일
은 거의 없기 때문
--> 이미 수 많은 기능이 개발
되어있기 때문에 필요한 거의 모든 것이 이미 존재
스프링 MVC의 핵심 구조
를 알아야 향후 문제가 발생
했을 때 어떤 부분에서 발생했는지 파악이 가능
( 개요 )
스프링 MVC의 구조
에서 핵심적인 역할
을 하는 것은 크게 3가지
- 핸들러 매핑 :
url에 해당
하는 핸들러를 조회
- 핸들러 어댑터 :
핸들러를 처리
할 수 있는 핸들러 어댑터 (실제 핸들러 호출)
- 뷰 리졸버 :
논리이름
을 파일의 실제 물리주소
로 변환
- 이 중
핸들러 매핑 / 핸들러 어댑터
가 스프링 MVC에서 어떻게 구체적으로 동작
하는지 이해해보자
지금은 사용하지 않는 인터페이스
를 통해 내부 동작 흐름
을 쉽게 이해
할 수 있다
( 핸들러 매핑 / 핸들러 어댑터 동작 이해 ) - Controller 인터페이스를 활용
지금은 사용하지 않는
Controller라는 인터페이스
를 상속
한 OldController가 호출되는 과정
을 알아보자
- 우선 해당
핸들러(컨트롤러)
가 호출
되려면 2가지가 필요
- HandlerMapping(핸들러 매핑)
: 해당 url 경로를 처리
할 수 있는 핸들러 매핑
을 찾고 해당하는 핸들러 반환
ex) 스프링 빈의 이름
으로 핸들러를 찾을 수 있는 핸들러 매핑
이 필요
- HandlerAdapter(핸들러 어댑터)
: 핸들러 매핑
을 통해서 찾은 핸들러
를 실행할 수 있는 핸들러 어댑터
가 필요
ex) Controller 인터페이스를 실행
할 수 있는 핸들러 어댑터
를 찾고 실행
- HandlerMapping / HandlerAdapter
처리 우선순위
0 = RequestMappingHandlerMapping
1 = BeanNameUrlHandlerMapping
...
0 = RequestMappingHandlerAdapter
1 = HttpRequestsHandlerAdapter
2 = SimpleControllerHandlerAdapter
...
- 동작 순서
- 핸들러 매핑 찾기 & 핸들러 반환
HandlerMapping
을 순서대로 실행
해서 실행할 수 있는 핸들러 매핑
을 찾아야 함
- 이 경우
빈(Bean) 이름
으로 핸들러를 찾아야 하기 때문
에 BeanNameUrlHandlerMapping
을 찾음
(HandlerMapping 처리 우선순위
에서 1
에 해당)
- 찾은 핸들러인
OldController
를 반환
- 핸들러 어댑터 조회
HnadlerAdapter
의 supports()
를 순서대로 호출
하며 처리할 수 있는 핸들러 어댑터
를 찾음
- 이 경우에
SimpleControllerHandlerAdapter
가 Controller 인터페이스를 지원
하므로 대상
이 됨
(HandlerAdapter 처리 우선순위
에서 2
에 해당)
- 핸들러 어댑터 실행
- 위에서
찾은 핸들러 어댑터
인 SimpleSontrollerHandlerAdapter
를 통해 실제 OldController 실행
ModelAndView 객체를 반환
( 뷰 리졸버 - viewResolver )
논리 뷰 이름
을 통해서 실제 물리 주소
로 매핑
해주는 역할
스프링 부트
가 자동 등록
하는 뷰 리졸버
0 = BeanNameViewResolver
1 = InternalResourceViewResolver
스프링 부트
는 JSP 사용
을 위해 InternalResourceViewResolver
라는 뷰 리졸버
를 자동으로 등록
application.properties
에 prefix / suffix설정 정보를 사용
해서 등록해야 함
- spring.mvc.view.prefix :
/WEB-INF/views
- spring.mvc.view.suffix :
.jsp