5. 스프링 MVC - 구조 이해 [전체 구조, 핸들러 매핑과 핸들러 어댑터, 뷰 리졸버]

이건회·2022년 7월 5일
0

springmvc

목록 보기
19/29

1) MVC 전체 구조

  • 이전까지 직접 만들었던 스프링 mvc 구조다.


  • 이제 실제 스프링 MVC의 모습이다. 동작 구조가 완전히 같다. 그러나 명칭에만 차이가 있다.
  • 프론트 컨트롤러는 디스패쳐 서블릿으로 칭한다. 이게 젤 중요하다.
  • 디스패쳐 서블릿도 서블릿이므로, httpServlet을 상속 받아 서블릿으로 동작한다.
  • 스프링부트는 디스패쳐 서블릿을 서블릿으로 자동으로 등록하면서, "모든 경로"에 대해서 매핑한다. 어떤 하위 경로에도 디스패쳐 서블릿이 호출되는 것이다.

* 요청 흐름

  • 서블릿이 호출되면 HttpServlet이 제공하는 service()가 호출된다.
  • 스프링 MVC는 DispatcherServlet 의 부모인 FrameworkServlet 에서 service() 를 오버라이드 해두었다.
  • FrameworkServlet.service() 를 시작으로 여러 메서드가 호출되면서 DispacherServlet.doDispatch() 가 호출된다. -> 제일 중요, 핸들러 찾아서 호출해주는 코드다.

* DispacherServlet.doDispatch() 동작과정

  • 먼저 핸들러를 조회한다.

  • 핸들러를 처리할 수 있는 어댑터를 찾는다
  • 어댑터를 실행하면-> 핸들러 어댑터 통해 핸들러 실행되고, ModelAndView가 반환된다.

  • viewResolver를 통해 뷰를 찾는다

  • 뷰를 반환한다

  • 뷰를 통해 processDispatcherResult가 렌더링을 호출한다.

  • 스프링 MVC의 장점은 디스패쳐 서블릿 코드의 변경 없이 원하는 기능을 변경할 수 있다는 것이다!

*2) 핸들러 매핑과 핸들러 어댑터

  • 먼저 이전 방식의 스프링 컨트롤러를 구현해보겠다. Controller를 implements한 컨트롤러를 만들어 준다.
  • 스프링 빈 이름을 컴포넌트 스캔을 통해 "/springmvc/old-controller" 로 명시해준다.


  • 빈 이름으로 url 요청을 보내면 콘솔에 출력이 되어 컨트롤러가 호출됨을 확인한다.
  • 콘솔에 출력되려면 두 가지가 필요하다
  • 먼저 핸들러 매핑에서 스프링 빈의 이름으로 핸들러를 찾아 가져올 수 있어야 한다.
  • 또 찾아온 핸들러를 실행할 수 있는 핸들러 어댑터를 찾고 실행해야 한다.
  • 핸들러 매핑, 핸들러 어댑터가 필요하다!

  • 핸들러 매핑은 먼저 어노테이션 기반의 컨트롤러인 @RequestMapping을 찾는다. 또 이후 스프링 빈의 이름으로 url과 똑같은 이름의 핸들러를 찾는 @BeanNameUrlHandlerMapping 으로 찾는다.

  • 핸들러 어댑터도 다음과 같은 방법이 있다.

따라서 최종적으로 OldController 동작 순서는 다음과 같다.

  1. 핸들러 매핑으로 핸들러 조회
    1-1) HandlerMapping 을 순서대로 실행해서, 핸들러를 찾는다.
    1-2) 이 경우 빈 이름으로 핸들러를 찾아야 하기 때문에 이름 그대로 빈 이름으로 핸들러를 찾아주는 BeanNameUrlHandlerMapping가 실행에 성공하고 핸들러인 OldController 를 반환한다.

  2. 핸들러 어댑터 조회
    2-1) HandlerAdapter 의 supports() 를 순서대로 호출한다.
    2-2) SimpleControllerHandlerAdapter 가 Controller 인터페이스를 지원하므로 대상이 된다.

  3. 핸들러 어댑터 실행
    3-1) 디스패처 서블릿이 조회한 SimpleControllerHandlerAdapter 를 실행하면서 핸들러 정보도 함께 넘겨준다.
    3-2) SimpleControllerHandlerAdapter 는 핸들러인 OldController 를 내부에서 실행하고, 그 결과를 반환한다.

정리하자면 OldController 를 실행하면서 사용된 객체는 다음과 같다.
HandlerMapping = BeanNameUrlHandlerMapping
HandlerAdapter = SimpleControllerHandlerAdapter

  • 이번에는 핸들러 어댑터로 HttpRequestHandlerAdapter를 써보겠다.

  • 핸들러를 세팅해주고 스프링 빈 이름을 지정해준 뒤, 출력 문구를 정해준다.


  • 빈 이름으로 url 요청을 보내면 문구가 출력된다.

  • 동작 방식은 다음과 같다
    1) 먼저 핸들러 매핑으로 빈 네임을 통해 핸들러를 찾는다.
    2) 핸들러를 찾으면 어댑터를 뒤져 HttpRequestHandler 어댑터를 찾아 가져온다.
    3) 핸들러 어댑터의 handle이 디스패쳐 서블릿에서 호출되고 그 결과를 반환한다.
    4) 최종적으로 handleRequest를 호출하고 우리가 지정한 문구가 호출되는 것이다.

  • 하지만 가장 우선순위가 높은 핸들러 매핑과 어댑터는 @RequestMappingHandlerMapping @RequestMappingHandlerAdapter 이다.

3) 뷰 리졸버

  • OldController에서 ModelAndView를 반환하고 논리적 이름인 "new-form"을 넣어보자


  • 서버를 실행하면 오류 페이지가 나오지만 컨트롤러는 호출이 된다. 즉 컨트롤러는 호출되는데 뷰가 없어 오류 페이지가 나오는 것이다.
  • 따라서 뷰 리졸버가 필요하다.

  • application.properties 에 다음 코드를 추가해 물리 주소로 변환할 url을 넣어준다.

  • 이제 정상적으로 뷰가 호출된다. 스프링 부트는 InternalResourceViewResolver 라는 뷰 리졸버를 자동으로 등록하는데, 스프링 부트가 application.properties 에서 설정정보를 가져와 등록해주었기 때문이다.
  • 참고로 그냥 물리정보를 직접 적어도 동작은 한다.

  • 스프링 부트 뷰 리졸버에는 스프링 빈 이름으로 뷰를 찾아 반환하는 BeanNameViewResolver와 JSP를 처리할 수 있는 뷰를 반환하는 InternalResourceViewResolver가 있다.
  • InternalResourceViewResolver가 방금 사용한 리졸버다. 내부에서 자원을 찾을 때 사용한다. jsp처럼 forward를 사용해 실행한다.
  • JSP의 경우 forward를 통해 해당 jsp로 이동해야 렌더링이 된다. jsp를 제외한 나머지 뷰 템플릿은 forward 없이 자동 렌더링 된다.
profile
하마드

0개의 댓글