본문 바로가기

개발/Spring

[Spring] Spring MVC 전체 구조

Spring 구조를 보기에 앞서, Servlet에 대한 포스팅을 먼저 참고하면 좋을 것 같다.

https://ttungbab.tistory.com/148 (Servlet 관한 포스팅)

 

 

Spring MVC 전체 구조

https://jinyoungchoi95.tistory.com/31

Spring MVC는 Dispatcher Servlet을 Front로 두고, 컨트롤러들을 어댑터를 통해 관리한다.
+ 이 Dispatcher Servlet은 자바 웹 MVC에서 FrontController와 동일한 역할이다.

https://github.com/freev5/TeamProject/blob/c57dffea24/src/com/tp/controller/FrontController.java
(실제 JSP Servlet으로 FrontController를 구현한 코드이다. 참고해도 괜찮겠다)

 

자바 JSP Servlet MVC에 대한 추가 설명

더보기

+ 자바 웹 MVC에서의 Front Controller에 대한 설명 

정말 중요하기 때문에 한번만 더 집고 넘어가겠다.

 

JSP Servlet의 구현하는 과정

JSP의 Servlet구현체는 5개의 추상 메소드를 구현해야 하는데(init( ), service(), destory(), getSErvletInfo(), getSErvletConfig()) 정보나 환경설정 같은 경우는 매번 똑같으니까 중복되는 것은 구현하고, 나머지는 추상 메소드로 남긴 추상 클래스 HttpServlet을 하나 더 만든 다음에, 이걸 상속해서 구현한다.

 

MVC 탄생

그리고 MVC 패턴이 적용된 것이다.

MVC패턴은 어떻게 구현이 되어있냐면, Servlet을 관리해주는 Tomcat에 web.xml에 FrontController하나만 넣어준 후, FrontController에서 모든 요청을 처리해준다.

 

 

FrontContoller구현 과정

 

1. HttpServlet을 상속한다. 추상 메소드 중, init, service를 override한다. 

 

2. Controller라는 Interface를 만든다.

3. 비즈니스 로직을 처리하는 여러 Controller클래스를 만든 후, 각 클래스는 Controller인터페이스를 구현한다.

 

4. 그리고 FrontController의 init에서는 HashMap에 각 Controller들을 put해준다.

 

5. service에서는 클라이언트가 요청한 uri에서 요청 메소드 부분을 파싱한 후, 그에 맞는 Controller를 HashMap에서 실행하고 반환해준다.

 

 

+ HttpServlet 공식 문서: https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html

 

 

 

FrontController의 구현

 

+ HttpServlet 공식 문서: https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html

 

Spring의 DispatcherServlet의 역할과 세부과정

 

Dispatcher Servlet또한 실제로 구현이 되어있는 모습을 보면 HttpServlet을 상속받고 있어 하나의 Servlet으로 동작하고 있음을 확인할 수 있다.

 

JSP Servlet에서 HttpServlet을 상속받으면, init, service 등 override 해야했었다.
하지만 스프링에서는 이것을 더 추상화 하였다.
FrameworkServlet에서 service()가 override되어있다.

이를 시작으로 DispatcherServlet.doDispatch()가 호출된다 - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html

 

Spring MVC 구조의 요청과 처리과정 요약

FrontController에서 했던 과정을 Dispatcher Servlet이 하게 된다.
  • 매핑된 값을 가지고 핸들러를 조회한다.
  • 조회된 핸들러를 처리할 어댑터를 조회한다.
  • 핸들러 어댑터를 통해 핸들러를 실행한다.
  • Model과 View를 핸들러에게 받는다.
  • 뷰 랜더링한다. (뷰 리졸버를 통해 실제 뷰 위치를 받는다)

 

 

하지만,, 요약본을 보았을 때 한번에 이해가 가지 않아, 요청과 처리 과정을 디버깅하며 코드를 뜯어보았다.

DispatcherServlet의 요청과 반환 과정

더보기

Spring이 실행하게 되면, 스프링 IoC컨테이너가 Bean들을 생성하여 등록 후 관리하게 된다.

 

그러던 중, 클라이언트로부터 요청이 들어왔다.

 이후 Spring에서 내부적으로 어떠한 과정을 거치는지 살펴보겠다.

 

1. doService()실행

처음 요청이 들어오면, DispathcerServlet이 요청을 받은 후, doService()를 실행하게 된다.

doService()에서 기본적인 request를 설정하다, doDispatch()를 실행한다.

 

2. doDispatch() 실행

 

요청이 multipart(이미지와 같은 것)인지 등 다른 상황을 체크해주다가, getHandler를 실행하게 된다.

 

3. getHandler()실행

RequestMappingHandlerMapping은 @PostMapping, @GetMapping등을 찾아주는 역할을 해준다.
저렇게 해서 mappedHandler에는 그에 맞는 Mapping을 찾아서 넣어준다.
즉 HandlerMapping: 요청에 맞는 핸들러를 찾아주는 인터페이스이다.

 

4.getHandlerAdapter()실행

요청에 맞는 handler를 찾았다면 mappedHandler는 null이 아니니, getHandlerAdapter를 실행해준다. getHandlerAdapter: 핸들러를 실행하는 인터페이스이다.
getHandlerAdapter를 통해, 주어진 handler를 실행할 수 있는 Adapter를 찾아온다.

 

 

주어진 getHandler를 찾아온 후, 이것을 실행시킬 수 있는 handlerAdapter를  찾아온다.

 

 

그러면 실행하기 전에, http가 "GET이라면 캐싱정보를 지원해준다.(중요한건 아님)
그리고 드디어 가져온 handler를 mv = ha.handle을 통해 요청을 처리한다.

5. handle()실행

드디어 실행된 handle안에서 handleInternal이라는 것을 실행하게 된다.

 

6. handleInternal실행, invokeHandlerMethod실행

주어진 handler메소드를 실행하기 위해, invokeHandlerMethod가 실행되게 된다.
invokeHandlerMethod가 필요에 따라 자바의 리플렉션을 사용하는 등을 거쳐, 메소드 실행 결과를 가져온다.

7. 드디어 결과 반환

전부 처리된 메소드가 리턴되며, 마무리된다.

 

참고:https://jinyoungchoi95.tistory.com/31