Spring MVC

김현정·2025년 3월 18일
0

Spring MVC 구조

Spring은 MVC패턴에 프론트 컨트롤러 패턴, 어댑터 패턴이 적용된 구조를 가지고있다.

  • Spring MVC 구조
    • DispatcherServlet : Spring의 프론트 컨트롤러
    • View : 인터페이스로 구성되어 있다, 확장성을 가지고 있다.
  • 실행순서
    1. Client로 부터 HTTP 요청(Request)을 받는다.
    2. Handler 조회
      • Handler Mapping을 통해 요청 URL에 Mapping된 Handler(Controller)를 조회
    3. Handler를 처리할 Adapter 조회
      • Handler를 처리할 수 있는 Handler Adapter를 조회
    4. Handler Adapter 실행(handle)
      • 알맞은 **어댑터가 존재한다면 **Handler Adapter에게 요청을 위임한다.
    5. Handler 실행(호출)
      • Handler Adapter가 실제 Handler(Controller)를 호출하여 실행 및 결과 반환
    6. Model And View 반환(return)
      • Handler Adapter는 Handler가 반환 하는 정보를 ModelAndView 객체로 변환하여 반환
    7. viewResolver 호출(알맞은 View 요청)
      • View Resolver를 찾고 실행
    8. View 반환
      • View Resolver는 View의 논리 이름을 물리 이름으로 전환하는 역할을 수행하고 Rendering 역할을 담당하는 View 객체를 반환
    9. View Rendering
      • View를 통해서 View를 Rendering
  • 요약
    • DispatcherServlet
      1. 클라이언트 HTTP Request를 알맞게 파싱하고 클라이언트에게 알맞은 응답을 반환
      2. 핸들러 목록 정보를 알고있다.
      3. 핸들러 어댑터 목록 정보를 알고있다.
    • HandlerAdapter
      1. 자신이 처리할 수 있는 Handler인지 확인할 수 있는 기능(Method)이 필요하다.
      2. 프론트 컨트롤러에서 요청을 위임받았을 때 핸들러에게 요청을 지시하는 기능이 필요하다.
      3. return 시 Handler로부터 전달받은 결과를 알맞은 응답으로 변환한다.
    • Handler
      1. 요청에 대한 로직을 수행하는 기능이 필요하다.

Dispatcher Servlet

  • Spring MVC의 프론트 컨트롤러는 Dispatcher Servlet(Servlet의 한 종류)이다.
    → Spring MVC의 핵심 기능

  1. Dispatcher Servlet은 HttpServlet을 상속 받아서 사용하고 Servlet의 한 종류이다.
  2. Spring Boot는 Dispatcher Servlet을 서블릿으로 자동으로 등록(내장 Tomcat WAS를 실행하면서 등록한다)하고 모든 URL 경로에 대해서 Mapping 한다. → (urlPatterns=”/”)
  3. 더 자세한 URL 경로가 높은 우선순위를 가진다.
    • 개발자가 만들 Servlet이 항상 우선순위가 높아서 실행된다.
  • DispatcherServlet의 service()
    - Servlet이 호출되면 HttpServlet이 제공하는 service()가 호출된다.
    • Spring MVC는 DispatcherServlet의 부모인 FrameworkServlet에서 service()를 Override 해두었다.
    • FrameworkServlet.service()를 시작으로 여러 메서드가 호출됨과 동시에 가장 중요한DispatcherServlet.doDispatch()가 호출된다.
protected void doDispatch() {
...
// 1. 핸들러 조회
	mappedHandler = getHandler(processedRequest); 
	if (mappedHandler == null) {
		noHandlerFound(processedRequest, response); // NotFound 404
	}

// 2. 핸들러 어댑터 조회 : 핸들러를 처리할 수 있는 어댑터
	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 3. 핸들러 어댑터 실행
// 4. 핸들러 어댑터를 통해 핸들러 실행 
// 5. ModelAndView 반환 
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 여기 안에서 render   
	processDispatchResult(processedRequest, response, mappedHandler, mv,dispatchException);
	...
}


// processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		if (mv != null && !mv.wasCleared()) {
			// View Render 호출
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
}

// render()
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	View view;
	String viewName = mv.getViewName();

// 6. ViewResolver를 통해 View 조회
// 7. View 반환
	view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

// 8. View Rendering
	view.render(mv.getModelInternal(), request, response);
}

Spring MVC의 주요 Interface

  • Spring MVC는 DispatcherServlet 코드의 변경 없이 기능변경 및 확장이 가능하다. 기능들이 대부분 Interface로 만들어져 있기 때문이다.
    -> 인터페이스를 implements 하여 구현하면 내가 만든 클래스를 사용할 수 있다. (객체지향의 다형성)

  • org.springframework.web.servlet

    1. HandlerMapping
    2. HandlerAdapter
    3. ViewResolver
    4. View

-> 구성 요소들을 다 알필요는 없지만 파악은 해놓기!

Controller Interface

  • Controller Interface를 implements 하여 구현하게되면 개발자가 원하는 Controller(Handler)를 사용할 수 있게됩니다.
    -> @Controller(Annotation) 역할이 비슷하지만 연관이 없다.


1. Handler Mapping
- 핸들러 매핑에서 ExampleController를 찾을 수 있어야 한다.
→ Spring Bean의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요하다.
2. Handler Adapter
- Handler Mapping을 통해 찾은 핸들러를 실행할 수 있는 Handler Adapter가 필요
→ Controller Interface를 실행할 수 있는 Handler Adapter를 찾고 실행한다.

- **HandlerMapping**
    - 우선순위 순서
    1. **RequestMappingHandlerMapping**
        - 우선순위가 가장 높다
        - Annotation 기반 Controller의 `@RequestMapping`에 사용
    2. BeanNameUrlHandlerMapping(위 예시코드에 사용)
        - Spring Bean Name으로 HandlerMapping

- **HandlerAdapter**
    - 우선순위 순서
    1. **RequestMappingHandlerAdapter**
        - Annotation 기반 Controller의 `@RequestMapping`에서 사용
    2. HttpRequestHandlerAdapter
        - HttpRequestHandler 처리
    3. SimpleControllerHandlerAdapter(위 예시코드에 사용)
        - Controller Interface 처리

0개의 댓글