Java/Spring

SpringMVC (3) - SpringMVC

태감새 2023. 4. 27. 23:09

이전글

 

SpringMVC (1) - WAS와 WebServer

목표 클라이언트 요청 시 응답을 받기까지 흐름 이해하기. WAS와 WebServer의 개념과 차이점 이해하기. WAS가 있어도 WebServer를 같이 사용하면 좋은점 이해하기. 클라이언트-서버 통신 기본적인 통신

han98-dev.tistory.com

 

SpringMVC (2) - Servlet Container와 Spring Container

목표 Servlet이 뭔지 알고 Servlet Container 동작방식 이해하기 Front Controller의 개념 이해하기 Spring Container와 Bean 이해하기 Bean을 등록하는 방법 알기 Servlet Container 이전 글에서 WAS에 대해서 알아보았다

han98-dev.tistory.com


목표

  • dispatcherServlet 이해하기
  • SpringMVC 패턴의 흐름 이해하기
  • 각각의 요소가 무슨 역할을 하고 왜 있는지 이해하기

DispatcherServlet

앞선 포스팅에서 FrontController를 구현하여 모든 요청을 받을 다음에 if문으로 URI별로 분기하여 요청을 처리하였다. 이렇게 모든 요청을 받고 URI에 맞는 핸들러를 찾아서 요청을 위임하는 일은 Spring에서는 DispatcherServlet이 한다. 그래서 코드는 아래와 같이 작성된다.

public class MemoApplication {  
    public static void main(String[] args) {  
    // 톰캣 서버 
    ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(); 
    // 웹서버
    WebServer webServer = serverFactory.getWebServer(servletContext -> {  
        servletContext.addServlet("dispatcherServlet",  
            new DispatcherServlet(applicationContext)  
            ).addMapping("/*");    // 모든 url을 받는다.  
    }); 
    webServer.start();
    }  
}

DispatcherServlet은 HttpMethod를 상속받는다.

 

하지만 이렇게 작성하면 오류가 발생한다. 왜일까?
FrontController에서 if문으로 URI별로 분기를 해줬는데 DispatcherServlet에서는 그런 처리를 해주지 않았기 때문에 어느 핸들러를 사용해야 할 지 알수가 없기 때문이다. 그렇다면 어떻게 DispatcherServlet한테 정보를 넘겨줄 수 있을까?

어노테이션을 이용한 Mapping

@Controller
public class HelloController {  
    HelloService helloService;  

    public HelloController(HelloService helloService) {  
        this.helloService = helloService;  
    }  

    @GetMapping("/hello")  
    @ResponseBody
    public String hello(String name) {  
        return helloService.sayHello(Objects.requireNonNull(name));  
    }  
}

아래의 @GetMapping과 같은 어노테이션을 이용하면 DispatcherServlet에서 Mapping 정보를 알 수 있다. 아래의 @ResponseBody@Controller에서는 기본적으로 String을 반환하면 view name으로 인식하고 view파일을 찾는다. 만약 view가 아닌 문자열 그대로를 반환하려면 어떻게 해야할까? 그때 @ResponseBody를 이용해서 문자열 그대로를 반환할 수 있다.

SpringMVC

지금까지 정리한 내용을 요약해보자

  • Tomcat 객체를 생성해서 서블릿을 하나 추가한 뒤 서버 실행
    • hello Servlet
  • 공통 로직 구현을 위해 FrontController 구현
  • SpringContainer에 객체를 bean으로 등록하여 필요한 객체 사용
  • FrontController -> DispatcherServlet 전환

이제 요청이 DispatcherServlet까지 오는 방법을 알았으니 요청을 받은 DispatcherServlet이 Spring MVC에서 어떻게 요청을 처리하는지 알아보자.

 

 

많은 처리를 거쳐서 클라이언트에게 응답이 나간다. 과정을 하나씩 살펴보자.

1. 핸들러 매핑

핸들러를 찾는 과정이다. 앞서서 @GetMapping과 같은 어노테이션으로 Mapping 정보를 입력했었다. DispatcherServlet은 요청 URI를 분석하여 이 요청을 처리할 핸들러를 찾는다.

2. 핸들러 어댑터 조회

핸들러는 알겠는데 핸들러 어댑터는 뭘까? 그리고 핸들러를 사용해서 로직을 처리하면 되는데 왜 핸들러 어댑터라는 것을 사용하는 것일까?

 

우선 어댑터에 대해서 알아야한다. 어댑터는 쉽게 생각하면 해외에 갔을 때 110V를 사용하기 위해서 220V 콘센트에 꼽는 변환기를 의미한다. 이처럼 서로 일치하지 않는 타입을 연결하기 위해서 어댑터를 사용한다.

 

요청을 처리하는 핸들러는 항상 같은 타입을 반환하지 않는다. 위의 예시처럼 String을 반환할 수도 있고 ModelAndView를 반환할 수도 있고 반환타입은 고정적이지 않다. 하지만 DispatcherServlet에서의 handle 메서드의 반환 타입은 ModelAndView로 정해져있다. 이렇게 다른 타입을 연결하기 위해서 핸들러 어댑터를 사용해서 핸들러에게 요청을 보내는 것이다.

3. 핸들러에게 요청 위임

위의 설명처럼 핸들러 어댑터를 이용해서 핸들러에게 요청을 보낸뒤 DispatcherServlet은 ModelAndView 타입의 응답을 받는다. ModelAndView는 이름 그대로 Model과 View의 이름을 가지고 있다.

4. ViewResolver 호출

ModelAndView의 view의 이름을 가지고 viewResolver를 통해서 view를 가지고 온다.

5. view render

viewResolver를 통해서 가져온 view로 render를 한다. 이때 model도 매개변수로 가져가서 렌더링을 해준다.

'Java > Spring' 카테고리의 다른 글

[Spring] AOP  (0) 2023.05.02
[Spring] IoC/DI  (0) 2023.05.01
JPA 간단정리  (0) 2023.04.25
[Spring] QueryString 객체로 받기  (0) 2023.04.23
[Spring] Github Action 적용하기 (+ properties 추가)  (0) 2023.04.23