Spring WEB DispatcherServlet 주요 흐름 분석

선종우·2023년 6월 23일
0

1. 주요 흐름

|doDispatch
  |->getHandler(processRequest) : return mappedhandler
     |->DisptacherServlet.handlerMappings에 대해  for loop 돌면서 request url에 대한 Handler 찾음
     |->(HandlerMapping) mapping.gethandler(request) : mappedHandler 반환
        |->getHandlerInternal(request)
           |->super.getHandlerInternal(request) super : AbstractHandlerMethodMapping
              |->initLookupPath(request) : /argument-resolver/
                 |->getRequestPaht(request) : requestPath
                 |-> requestPath.pathWithApplication.value() : /argument-resolver/
              |->lookupHandlerMethod(lookupPath, request)
                 |->bestMatch.getHandlerMethod()
                    |->getHandlerInternal(request) : HandlerMethod handlerMethod 반환
        |->handler가 없으면 getDefaultHandler() 호출, getDfaultHandler()null이면 null 반환
        |->getHandlerExecutionChain() 여기서 interceptor붙임
        |->cors 관련 수행
     |->getHadnlerAdapter(mappeedHandler.getHandler()) : HandlerAdapter ha 
        |->adapter.supports(handler) handlerAdapters를 순회하며 adapter가 handler를 지원하는 지 확인
     |->mappedHandler.applyPreHandler(processedRequest, response) 
        |->HandlerExecutionChain 내의 interceptor 순회
        |->interceptor.preHandle()
           |-> False일 경우 triggerAfterCompletion()
     |->ha.handle(processedRequet, response, mappedHandler.getHandler() : return ModelAndview
        |->handleInternal
           |->invokeHandlerMethod
              |->createInvocableHandlerMethod(handlerMethod)  : ServletInvocableHandlerMethod invocableMethod 생성
              |->invocableMethod.sethandlerMethodArgumenResolvers(this.argumentResolvers)
              |->invocableMethod.setHandlerMethodRturnValueHandlers(this.returnValueHandlers)
                 (많이 생략)
              |->invocableMethod.invokeAndHandle(webRequest, mavContainer)
                 |->invokeForRequest : resolve된 argument args 반환
                    |->getMethodArgumentValues : argument를 순회하며 argumentrResolver 적용
                       |->getMethodParameters()
                       |->this.resolvers.supportsParameter(parameter)
                          |->getArgumentResolver(parameter)
                             |->resolver.supportsParameter(parameter) for문으로 argumentResolver를 순회하며 argumentResolver가 parameter를 지원하는지 체크
                             |->this.argumentResolverCache.put(parameter, result)
                             |->resolver가 없으면 IllegaStateException 발생
                          |->resolveArgument()
                             |-> getArgumentResolver(parameter)
                             |-> resolver가 없으면 IllegalArgumentException 발생
                             |-> resolveArgument() : 처리된 argument object 반환
                 |->doInvoke(args)
                    |->method.invoke 내가 구현한 로직 실행
                 |->setResponseStatus
                 |->retunValueHandlers.handleReturnValue()
                    |->selectHandler()
	                   |->returnValueHandlers를 순회하며 HandlerMethodRturnValueHandler가 returnType을 지원하는지 확인
                       |-> 지원하면 handler 반환
                    |->handlReturnValue
                       |->mavContainer.setViewName(viewName)
                 |->getModelAndView
           |-> prepareResponse(response)
     |->mappedHandler.applyPostHandler()
     |->processDispatchResult()
        |->processHandlerException(익셉션이 발생한 경우)
            |->resolver.resolveExcepion() : resikver(HandlerException)을 순회하며 exMv(ModelAndView)를 반환, exMv가 있으면 순회 중단
               |->doResolveException()
                  |->doResolveHandlerMethodException() : ExceptionHandler 기준
                     |->getExceptionHandlerMethod() : controller에 선언된 handlerMethod를 찾아서 ServeltInvocableHandlerMethod를 반환
                        |->ExceptionHandlerMethodResolver resolver = this.exceptionhandlerCache.computeIfAbsent(handlerType, ExceptionhandlerMethodResolver::new)
                        |->resolver.resolveMethod(exception) :만약 controller에 exceptionhandler가 있으면 반환하고 getExceptionHandlerMethod종료
                           |->resolveMethodByThrowable(exception)
                              |->getMappedMethod() : match되는 exceptionHandler아 있으면 그중 첫번째를 반환
                                 |->mappedException.isAssignableFrom(exceptionType) : Spring app 로딩될 때 (hashmap)mappedMethods에 (exception : exceptionhandler)가 담겨있다.
                                 |->만약 match되는 exceptoinhandler가 여러개면 ExceptionComparator로 sort한다
                                 |->exceptionLookupCache에 저장
                                 |->만약 controller에 설정된 ExHandler없으면 NO_MATCHING_EXCEPTION_HANDLER_METHOD반환
                        |->advice.isApplicableToBeanType(handlerType) : exceptionHandlerAdviceCache에 있는 advice를 순회하며 적절한 advic를 찾음
                        |->ExceptionHandlerMethodResolver resolver = entry.getValue()
                        |->resolver.resolveMethod() : 이후 로직은 위와 동일
                     |->invokeAndHandlerMethod() : 이후 controller의 handlerMethod처리 로직과 동일
        |->ExceptionHandlerModelAndView를 반환하지 못한 경우 throw Exception
        |->render()
           |->resolveVieName()
              |->view.render
        |-> trigerAfterCompletion

2. Spring에 내장된 각종 처리기들

1. HandlerMapping List

0 = {RequestMappingHandlerMapping@10593}
1 = {WelcomePageHandlerMapping@10594}
2 = {BeanNameUrlHandlerMapping@10595}
3 = {RouterFunctionMapping@10596}
4 = {WelcomePageNotAcceptableHandlerMapping@10597}
5 = {SimpleUrlHandlerMapping@10598}

2. HandlerAdapter list

0 = {RequestMappingHandlerAdapter@10744}
1 = {HandlerFunctionAdapter@10745}
2 = {HttpRequestHandlerAdapter@10746}
3 = {SimpleControllerHandlerAdapter@10747}

3. InterceoptorList

0 = {WebRequestHandlerInterceptorAdapter@10808}
1 = {ConversionServiceExposingInterceptor@10878}
2 = {ResourceUrlProviderExposingInterceptor@10889}
3 = {LogInterceptor@10890} #Custorm Interceptor order(1)로 하였음에도 spring 내장 interceptor보다 순서가 뒤에 있다.

4. ArgumentResolvers = HandlerMethodArgumentComposite

0 = {ProxyingHandlerMethodArgumentResolver@10963}
1 = {RequestParamMethodArgumentResolver@10964}
2 = {RequestParamMapMethodArgumentResolver@10965}
3 = {PathVariableMethodArgumentResolver@10966}
4 = {PathVariableMapMethodArgumentResolver@10967}
5 = {MatrixVariableMethodArgumentResolver@10968}
6 = {MatrixVariableMapMethodArgumentResolver@10969}
7 = {ServletModelAttributeMethodProcessor@10970}
8 = {RequestResponseBodyMethodProcessor@10971} -> @RequestBody 값 없으면 httpMessageNotReadableException
9 = {RequestPartMethodArgumentResolver@10972}
10 = {RequestHeaderMethodArgumentResolver@10973}
11 = {RequestHeaderMapMethodArgumentResolver@10974}
12 = {ServletCookieValueMethodArgumentResolver@10975}
13 = {ExpressionValueMethodArgumentResolver@10976}
14 = {SessionAttributeMethodArgumentResolver@10977}
15 = {RequestAttributeMethodArgumentResolver@10978}
16 = {ServletRequestMethodArgumentResolver@10979}
17 = {ServletResponseMethodArgumentResolver@10980}
18 = {HttpEntityMethodProcessor@10981}
19 = {RedirectAttributesMethodArgumentResolver@10982}
20 = {ModelMethodProcessor@10983}
21 = {MapMethodProcessor@10984}
22 = {ErrorsMethodArgumentResolver@10985}
23 = {SessionStatusMethodArgumentResolver@10986}
24 = {UriComponentsBuilderMethodArgumentResolver@10987}
25 = {LoginMemberArgumentResolver@10988} # Custom ArgumentResolver 순서 지정에 대해서는 추가 공부 필요
26 = {SortHandlerMethodArgumentResolver@10989}
27 = {PageableHandlerMethodArgumentResolver@10990}
28 = {ProxyingHandlerMethodArgumentResolver@10991}
29 = {PrincipalMethodArgumentResolver@10992}
30 = {RequestParamMethodArgumentResolver@10993}
31 = {ServletModelAttributeMethodProcessor@10994}

5. returnValueHandlers = HandlerMethodReturnValueHandlerComposite

0 = {ModelAndViewMethodReturnValueHandler@11001}
1 = {ModelMethodProcessor@11002}
2 = {ViewMethodReturnValueHandler@11003}
3 = {ResponseBodyEmitterReturnValueHandler@11004}
4 = {StreamingResponseBodyReturnValueHandler@11005}
5 = {HttpEntityMethodProcessor@11006}
6 = {HttpHeadersReturnValueHandler@11007}
7 = {CallableMethodReturnValueHandler@11008}
8 = {DeferredResultMethodReturnValueHandler@11009}
9 = {AsyncTaskMethodReturnValueHandler@11010}
10 = {ServletModelAttributeMethodProcessor@11011}
11 = {RequestResponseBodyMethodProcessor@11012}
12 = {ViewNameMethodReturnValueHandler@11013}
13 = {MapMethodProcessor@11014}
14 = {ServletModelAttributeMethodProcessor@11015}

6.HandlerExceptionResolverComposite

this.resolvers에
DefaulterrorAttributes와 HandlerExceptionResolverComposite있음
HandlerExceptionResolverComposite은 아래 리스트로 구성
0 = {ExceptionHandlerExceptionResolver@11386}
1 = {ResponseStatusExceptionResolver@11387}
2 = {DefaultHandlerExceptionResolver@11388}
3 = {MyHandlerExceptionResolver@11389} #custom Exception

7. exceptionHandlerAdviceCache

Map<ControllerAdviceBean, ExceptionHandlerMethodResolver>
exceptionHandlerAdviceCache(LikedHashMap) 안에 adivce와 이에 대한 resolver가 linkedHashMap으로 mapping되어 있음

8. messageConverters(HttpMessageConverter)

0 = {ByteArrayHttpMessageConverter@10991}
1 = {StringHttpMessageConverter@10992}
2 = {StringHttpMessageConverter@10993}
3 = {ResourceHttpMessageConverter@10994}
4 = {ResourceRegionHttpMessageConverter@10995}
5 = {SourceHttpMessageConverter@10996}
6 = {AllEncompassingFormHttpMessageConverter@10997}
7 = {MappingJackson2HttpMessageConverter@10998}
8 = {MappingJackson2HttpMessageConverter@10999}
9 = {Jaxb2RootElementHttpMessageConverter@11000}

0개의 댓글