여니의 프로그래밍 study/Spring & Spring Boot

[Spring] 스프링 mvc 프레임워크 동작 방식 (Chapter 10)

여니's 2023. 11. 25. 22:04

 

참고 자료 : 초보 개발자를 위한 스프링5 프로그래밍 입문

 

 


<Chapter 10. 스프링 MVC 프레임워크 동작 방식>

1. 스프링 MVC 핵심 구성 요소

 

DispatcherServlet은 모든 연결을 담당함

 

1) 웹 브라우저로부터 요청이 들어옴

 

2) DispatcherServlet은

해당 요청을 처리하기 위한 컨트롤러 객체를 검색함

(직접 조회하는 것이 아니라 HandlerMapping이라는

빈 객체에게 컨트롤러 검색을 요청함)

 

3) HandlerMapping은 클라이언트의 요청 경로를 이용하여

이를 처리할 컨트롤러 빈 객체를 DispatcherServlet에 전달

 

4) HandlerAdapter 빈에게 요청 처리를 위임한다.

 

5) HandlerAdapter는 컨트롤러의 알맞은 메서드를 호출해 요청을 처리하고 결과를 

DispatcherServlet에 리턴한다.

(이때, 컨트롤러의 처리 결과를 ModelAndView라는 객체로 변환하여 전달함)

 

6) 결과를 보여줄 뷰를 찾기 위해 ViewResolver 빈 객체를 사용함

(매번 새로운 View 객체를 생성해서 DispatcherServlet에게 리턴함)

 

7) DispatcherServlet은 ViewResolver가 리턴한 View 객체에게

응답 결과 생성을 요청함

 

 


1) 컨트롤러와 핸들러

: 클라이언트의 요청을 실제로 처리하는 것은 컨트롤러

DispatcherServlet은 클라이언트의 요청을 전달받는 창구 역할

 

스프링 MVC는 웹 요청을 실제로 처리하는 객체를

핸들러(Handler)라고 표현하고 있으며

@Controller 어노테이션 적용 객체나

Controller 인터페이스를 구현한 객체는 모두 핸들러에 속한다. 

 

 

2) DispatcherServlet과 스프링 컨테이너

: DispatcherServle은 스프링 컨테이너를 생성하고

그 컨테이너로부터 필요한 빈 객체를 구한다

 

 

3) @Controller를 위한 HandlerMapping과 HandlerAdapter

- HandlerMapping : 웹 브라우저의 요청을 처리할 핸들러 객체를 찾기 위해 사용

- HandlerAdapter : 핸들러를 실행하기 위해 사용

 

 

핸들러에 알맞은 HandlerMapping 빈과 HandlerAdapter 빈이

스프링 설정에 등록이 되어 있어야 한다. 

 

 

- RequestMappingHandlerMapping

: @Controller 어노테이션이 적용된 객체의 요청 매핑 어노테이션(@GetMapping)값을 이용하여

웹 브라우저의 요청을 처리할 컨트롤러 빈을 찾는다

 

 

- RequestMappingHandlerAdapter

: 컨트롤러의 메서드를 알맞게 실행하고

그 결과를 ModelAndView 객체로 변환해서

DispatcherServlet에 리턴한다.

 

 

@Controller
public class HelloController {
    @GetMapping("/hello") // 메서드가 처리할 요청 경로를 지정함
    public String hello(Model model, @RequestParam(value="name",required=false) String name) {
        model.addAttribute("greeting","안녕하세요" + name);
        return "hello";
    }
}

 

RequestMappingHandlerMapping 

> "/hello" 요청 경로에 대해 hello() 메서드를 호출함

model 객체를 생성하여 첫 번째 파라미터로 전달하고

name인 HTTP 요청 파라미터의 값을 두 번째 파라미터로 전달함

 

 

RequestMappingHandlerAdapter

> 컨트롤러 메서드 결과값이 String이면 

해당 값을 뷰 이름으로 갖는 ModelAndVIew 객체를 생성하여

DispatcherServlet에 리턴한다. 

 

 

4) WebMvcConfigurer

> @EnableWebMvc 어노테이션을 사용하면

@Controller 어노테이션을 붙인 컨트롤러를 위한 설정을 생성함

 

package config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/view/", ".jsp");
    }
}

 

 

> WebMvcConfigurer 타입의 빈 : MvcConfig 클래스

 

EnableWebMvc 어노테이션을 사용하면

WebMvcConfigurer 타입의 빈 객체의 메서드를 호출해서 

MVC 설정을 추가함

 

 

5) JSP를 위한 ViewResolver

 

package config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/view/", ".jsp");
    }
}

 

 

컨트롤러의 실행 결과를 받은 DispatcherServlet은

ViewResolver에게 뷰 이름에 해당하는 View 객체를 요청함

 

 


 

6) 디폴트 핸들러와 HandlerMapping의 우선순위

 

매핑 경로가 "/"인 경우

jsp로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet이 처리

 

/index.html이나 /css/bootstrap.css와 같이 확장자가 .jsp가 아닌 모든 요청을

DispatcherServlet이 처리함
 
그런데 @EnableWebMvc가 등록하는 HandlerMapping은

@Controller가 적용한 빈 객체가 처리할 수 있는 요청 경로만 대응 가능함


즉, 그 컨트롤러에서 @GetMapping("/hello")만 설정한다면

"/hello"이외의 다른 경로를 처리할 수 없게 되고

404 error를 내게 됩니다. 
이를 처리하기 위해 WebMvcConfigurer의 configureDefaultServletHandling 메소드를 사용함

 

 

 

웹 브라우저에서 요청이 들어오면

DispatcherServlet은

 

1. RequestMappingHandlerMapping를 사용해서 

요청을 처리할 핸들러를 검색함

> 존재하면 해당 컨트롤러를 이용하여 요청 처리함

 

2. 존재하지 않으면 SimpleUrlHandlerMapping을 사용해서

요청을 처리할 핸들러를 검색함.

->  DefaultServletHandlerConfigurer#enable() 메소드가 등록한

SimpleUrlHandlerMapping을 이용해 모든 경로 ("/**")에 대해

DefaultServletHttpRequestHandler를 리턴
-> DispatcherServlet은 DefaultServletHttpRequestHandler에 처리를 요청
-> DefaultServletHttpRequestHandler는 디폴트 서블릿에 처리를 위임