-
[Spring] MVC 동작 방식 디버깅을 통해 알아보기Server/Spring MVC 2021. 10. 23. 12:08728x90반응형
Spring MVC 프레임워크 동작 방식
Spring Boot, Spring MVC가 엄청난 설정들을 대신 해주기에 편리하게 사용할 수 있는 것인데요. Spring MVC를 구성하는 주요 요소가 무엇이고 각 구성 요소들이 서로 어떻게 연결되는지 정도는 이해하면 좋을 것 같아서 이번 글에서 정리해보려 합니다.
Spring MVC 핵심 구성 요소
위의 그림에서
<<spring bean>>
이라고 되어 있는 것들은Spring Bean
으로 등록해야 하는 것을 의미합니다. 그리고분홍색
으로 칠해져 있는 것은 개발자가 직접Spring Bean
으로 등록해야 하는 것을 의미합니다. 예를들어,@Controller
를 통해서 직접 Controller Class를 만든 후에 @Controller로 Bean으로 등록하는 것을 의미합니다.@Controller가 붙어 있을 때 실행되는 순서를 정리하면 아래와 같습니다.
- 제일 먼저 볼 것은
DispatcherServlet
인데요. 중앙에 위치한DispatcherServlet
은 모든 연결을 담당합니다. 먼저 클라이언트(브라우저)로 요청이 들어오면 그 요청을 처리할 Controller 객체를 검색합니다. - 이 때
DispatcherServlet
은 직접 검색하지 않고HandlerMapping
이라는 빈 객체에서 컨트롤러 검색을 요청합니다. DispatcherServlet
은HandlerMapping
이 찾아준 컨트롤러 객체를 처리할 수 있는HandlerAdapter
Bean에게 요청 처리를 위임합니다.- 그리고
HandlerAdapter
는 DispatcherServlet과 Handler 객체 사이의 변환을 알맞게 처리해 줍니다. 즉, 컨트롤러의 알맞은 메소드를 호출해서 요청합니다. - 4번의 결과를
DispatcherServlet
에게 return 합니다. HandlerAdapter
는 컨트롤러의 처리 결과를ModelAndView
라는 객체로 변환해서DispatcherServlet
에 return 합니다.HandlerAdapter
로 부터 컨트롤러의 요청 처리 결과를ModelAndView
로 받으면DispatcherServlet
은 결과를 보여줄 뷰를 찾기 위해ViewResolver
Bean 객체를 사용합니다.- 응답을 생성하기 위해 JSP를 사용하는
ViewResolver
는 매번 새로운 View 객체를 생성해서DispatcherServlet
에 return 합니다.
Spring MVC 디버깅 해보기
@RestController public class HelloController { @GetMapping public String hello() { return "Gyunny Hello"; } }
위처럼
@RestController
를 사용하는 컨트롤러 API에 접근할 때 내부적으로 어떤 일이 일어나는지 디버깅을 해보면서 알아보겠습니다.먼저
DispatcherServlet
에doService
메소드 첫 번째 줄에Break Point
를 찍어놓은 후에 디버그 모드로 실행하고, 위에서 작성한http://localhost:8080
에 요청을 보내보겠습니다. (참고로 디버거 모드에서 F7은 step into로 해당 메소드 내부 코드로 가는 것이고, F8은 다음 줄로 실행하는 것입니다.)F8을 통해서 계속 다음으로 가다 보면
doDispatch()
메소드가 나오는데요. 여기서F7
을 통해서 해당 메소드 내부로 가보겠습니다.메소드 내부 코드를 보면
getHandler
가 보이는데요. 이름으로 추측해보면 위의 그림에서 보았던HandlerMapping
과 관련된 곳인 것 같습니다.메소드 내부 코드를 보면
HandlerMappings
관련 코드가 보입니다.HandlerMappings
변수에 저희가 아무런 설정을 하지 않아도 위와 같이 6개의HandlerMapping
이 존재하는 것을 볼 수 있습니다. 어떤 핸들러가 사용되는지 보기 위해서 F8로 다음 코드로 계속 이동해보겠습니다.for문을 돌다보면
RequestMappingHandlerMapping
이 사용된 후에 for문이 종료되는 것을 볼 수 있습니다. 이렇게HandlerMapping
을 통해서 컨트롤러 Bean 객체를DispatcherServlet
에게 전달했을 것입니다.그리고 F8을 누르면서 다음으로 가보면
getHandlerAdapter
를 통해서 위에서 찾은Handler
를 실행할 수 있는Adapter
를 찾아오는 것을 볼 수 있습니다.메소드 내부로 들어가게 되면 이번에도 for문을 통해서 사용할 Adapter를 찾는 과정이 진행되는데요.
Adapter는 기본적으로 4개가 존재하는 것을 볼 수 있습니다.
디버깅을 계속 진행해보면,
RequestMappingHandlerAdapter
가 선택되어 실행되는 것을 확인할 수 있습니다. 이제 Handler를 실행할 수 있는HandlerAdpater
를 찾았습니다.그리고 위의 코드에서
HandlerAdapter
를 이용해서 요청을 처리하게 되는데요. 좀 더 보기 위해서 F8을 통해서 다음으로 계속 간 후에, 위의 코드에서 다시F7
을 통해서 내부 코드로 들어가보겠습니다.여기서도
handleInternal
내부 코드로 가기 위해서 F7을 누르겠습니다.그리고 F8을 통해서 다음으로 진행되는 코드를 보면
invokeHandlerMethod
가 보입니다. 여기서 자바의 리플렉션을 사용해서Controller
의 메소드를 실행하게 되는 것입니다.여기서 이미
handlerMethod
에 실행하고자 하는 Controller Method가 존재하는 것을 볼 수 있습니다.그리고 다음 F8을 통해서 이동하면
Controller Method
로 이동하는 것을 볼 수 있습니다. 계속 다음으로 이동해보겠습니다.그리고
return
값이 예상할 수 있듯이String
인 것도 확인할 수 있습니다.그리고 F8을 누르면서 다음으로 이동하면
returnValueHandlers.handleReturnValue
가 존재하는 것을 볼 수 있습니다. 현재 Controller는 @Controller를 사용하는 것이 아니라 @RestController를 사용하기 때문에 return 에는 여러가지 값이 들어갈 수 있습니다.위의 이름이
HandlerMethodReturnValueHandler
인 것을 보면 return 값의 타입에 따라 어떤 것을 선택할 지 정하는 것처럼 보이는데요. 이것도 디버깅을 해보면RequestResponseBodyMethodProcessor
이 사용됩니다.그리고 계속 쭉 F8로 실행을 하다 보면 위의 코드까지 오게 되는데요. mv는
ModelAndView
타입의 변수인데, 위의 사진을 보면null
인 것을 알 수 있습니다. 이유는 현재는@Controller
가 아닌@RestController
를 사용하기 때문에view
를 찾는 과정이 필요 없기 때문입니다. 이렇게 지금까지@RestController
가 존재하는 Controller에 요청이 오면 Spring MVC에 내부적으로 어떻게 동작하는지 디버거를 통해서 알아보았습니다. 간단하게? 본 것 같은데도 내부적으로 정말 복잡하게 이루어지는 것을 볼 수 있습니다.@Controller 어노테이션으로 View를 찾는 경우 디버깅
@Controller public class HelloController { @GetMapping public String hello() { return "login"; } }
이번에는
@Controller
어노테이션을 사용해서View
를 찾는 과정도Debug
를 통해서 알아보겠습니다. 위에서 정리한 내용과 비슷하기 때문에 차이점이 있는 부분만 정리해보겠습니다.똑같이 진행되다가 위에서 보았던
HandlerMethodReturnValueHandler
를 보면 이번에는ViewNameMethodReturnValueHandler
가 사용되는 것을 볼 수 있습니다.그리고 이번에는
@Controller
이기 때문에ModelAndView
에 제가 사용하는login
이라는 View 이름이 보이는 것을 볼 수 있습니다.또한
@Controller
이기 때문에ModelAndView
가 null이 아니라 값을 가지고 있는 것도 볼 수 있습니다.그리고 계속 디버깅을 해보면 위와 같이
View
와 관련된 코드를 만날 수 있는데요. 여기서 뭔가ViewResolver
와 관련된 것이 있을 것 같아서 좀 더 자세히 보았습니다.그러면 위와 같이
ViewResolver
가 사용되는 것을 볼 수 있습니다. 코드를 자세히 이해할 순 없지만.. 그래도 디버깅을 계속 돌려보았습니다.그러면
ViewResolver
인터페이스 구현체인ContentNegotiatingViewResolver
가 사용되면서 View를 찾는 과정을 볼 수 있습니다.이렇게 까지 계속 디버깅을 통해서 따라가본 이유는 내부 코드를 완벽하게 이해할 순 없지만, 대략적으로 위에서 정리했던 내용대로 실행되는 것인지 알아보면서 전체적인 흐름을 정리하기 위해서 보았습니다.
Reference
반응형'Server > Spring MVC' 카테고리의 다른 글
[Spring] MVC HttpSession, Interceptor, Cookie 정리하기 (0) 2021.10.20 [Spring] @Valid를 이용해 @RequestBody DTO 검증하기 (1) 2021.10.12 [Spring] MVC 기본 어노테이션과 Lombok 정리하기 (0) 2021.10.07 [Spring] 스프링 웹 계층이란? (6) 2020.08.26 [Spring] @MVC와 DispatcherServlet에 대해서 (0) 2020.07.25 - 제일 먼저 볼 것은