1. DispatcherServlet 기본 동작
DispatcherServlet.java
doService
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); ...
doDispatch 로 진입
멀티파트 요청(파일 업로드) 인지 확인
핸들러를 찾아오는 부분 : 해당 요청을 처리하는 핸들러를 찾아오는 부분 (대부분 전략 패턴을 통해 가지고 옴)
DispatcherServlet이 들고 있는 여러개의 핸들러 맵핑중 RequestMappingHandlerMapping 을 선택
해당 맵핑 핸들러가 우리가 설정한 Controller(url) 이나 get/post mapping 으로 지정한 핸들러를 찾아주는 객체
RequestMappingHandlerMapping 을 사용하여 핸들러를 찾아옴 [me.demo.HelloController#hello()]
핸들러 어뎁터를 찾아오는 영역, 핸들러 어뎁터는 핸들러를 실행해 주는 역할을 함
전달한 핸들러를 누가 실행할 수 있느냐를 찾는 과정
현 상태에서는 디스패처서블릿이 아래 그림과 같은 어뎁터를 가지고 있음
여기서는 RequestMappingHandlerAdapter 가 핸들러를 처리함
핸들러를 실행할 수 있는 어뎁터를 찾음
핸들러와 어뎁터 둘다 찾았다면 실행 전 Get 요청인지 확인 후 캐싱 처리를 함(304 Not Modified 요청을 할지)
HandlerAdapter 를 통해 핸들러를 처리함
// DispatcherServlet.java
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
...
try {
doDispatch(request, response);
}
...
}
...
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
...
try{
...
try {
processedRequest = checkMultipart(request); // 1
...
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest); // 2
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
...
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 4
...
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) { // 6
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
...
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 7
...
}
}
}
...
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 3
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
...
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) { // 5
return adapter;
}
}
...
}
...
}
AbstractHandlerMethodAdapter / RequestMappingHandlerAdapter
실제 핸들러 메소드를 리플랙션 기능을 실행하는 invoke 메소드를 실행
handlerMethod 라는 객체 안에는 이미 해당 핸들러 메소드에 대한 내용이 있음
리플랙션을 통해 해당 메소드를 호출함
// AbstractHandlerMethodAdapter.java ... @Override @Nullable public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } ...
// RequestMappingHandlerAdapter.java ... @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ... // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { ... } else { // No synchronization on session demanded at all... mav = invokeHandlerMethod(request, response, handlerMethod); // 1 } }
HelloController
- invoke 메소드가 실행이 되면 우리가 작성한 실제 메소드가 실행됨
// HelloController.java
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello() {
return "hello, " + helloService.getName(); // 1
}
}
ServletInvocableHandlerMethod
returnValue 에는 우리가 지정해둔 문자열 리턴값이 출력
// ServletInvocableHandlerMethod.java
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 1
setResponseStatus(webRequest);
HandlerMethodReturnValueHandlerComposite
- returnValueHandlers 를 찾음
- returnValueHandlers 는 핸들러에서 리턴한 값을 어떻게 처리할꺼냐?
- 문자열, ViewModel, ResponseEntity 등등을 리턴할 수 있기 때문
- 해당 코드에서는 String 이면서도 RestController 이기 때문에 ResponseBody 어노테이션이 붙어있는 리턴값임
- 그렇기 때문에 아래 여러개의 returnValueHandler 중 RequestResponseBodyMethodProcessor 가 처리를 담당함
- RequestResponseBodyMethodProcessor 핸들러는 컨버터를 사용해서 http 본문에 넣어주는 처리를 해줌
// HandlerMethodReturnValueHandlerComposite.java @Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { // 1 if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; }
- returnValueHandlers 를 찾음
응답값 리턴~!
'IT > Web' 카테고리의 다른 글
vue-cli global 설치후 command not found (0) | 2020.06.15 |
---|---|
radio tag 속성스코프에 설정한 값으로 checked 하기(jstl 사용) (0) | 2017.04.20 |
[펌]restfull api 제대로 만들기 (0) | 2016.11.29 |
확장성 있는 웹 아키텍쳐와 분산 시스템 (0) | 2016.10.17 |
RESTful API (0) | 2016.09.23 |