Java/Spring & Spring Boot

Servlet과 JSP 그리고 MVC(Model, View, Controller)

마손리 2023. 4. 11. 22:02

Servlet

서블릿은 클라이언트의 요청을 처리하고 해당 요청의 결과를 클라이언트에게 전송하는 자바 프로그래밍 기술이다. 

즉, 웹 어플리케이션을 동적으로 만들어주는 역할을 담당하고 있다. 

 

웹 어플리케이션은 요청과 응답으로 클라이언트와 백엔드 서버간에 소통을 하며 동적서비스를 만드는데 이때 Servlet container가 클라이언트의 요청을 받아 요청에 맞는 로직을 수행할 Servlet 객체를 생성하고 관리한다. 

 

(Spring에는 Tomcat이 내장되어있으며 이 Tomcat이 Servlet container 역할을 한다.)

 

Servlet 필수 메서드

  • init() - 서블릿 생성
  • service() - 처리 진행
  • destroy() - 서블릿 삭제

 

Servlet container의 역할

  • 요청과 응답을 이용하여 웹서버와 통신
  • 서블릿의 생명주기 관리
  • 멀티쓰레드 지원 및 관리
  • 선언적인 보안 관리

 

서블릿 필수 메서드를 통해 서블릿 컨테이너는 해당 서블릿 객체의 생명주기를 관리한다. 

 

또한 서블릿 객체는 싱글톤 패턴을 사용하기 때문에 하나의 요청과 응답을 끝내더라도 해당 서블릿 객체를 바로 삭제하지 않고 이후에 들어올 요청에 다시 사용하며 만약 같은 요청이 여러개가 한번에 들어오더라도 서블릿 컨테이너는 새로운 쓰레드를 이용하여 생성된 서블릿을 이용해 같은 요청을 동시적으로 진행한다. 

 

때문에 서블릿은 무상태 혹은 읽기 전용 상태로 설계되어야 한다.

서블릿 컨테이너의 멀티스레딩

Servlet의 동작 방식

  1. 웹서버가 HTTP 요청을 받는다.
  2. 웹서버는 요청을 서블릿 컨테이너로 전달
  3. 서블릿이 컨테이너에 없다면, 서블릿을 동적으로 검색하여 컨테이너의 주소 공간에 로드한다.
  4. 컨테이너가 서블릿의 init() 메소드를 호출하면, 서블릿이 초기화된다.(서블릿이 처음 로드됐을 때 한번만 호출)
  5. 컨테이너가 서블릿의 service() 메소드를 호출하여 HTTP 요청을 처리한다.(요청의 데이터를 읽고, 응답을 만들어낸다)
    • 컨테이너는 해당 서블릿을 바로 삭제하지않고 다음에 같은 요청들을 처리할때 다시 사용해준다.
  6. 웹서버는 동적으로 생성된 결과를 올바른 위치에 반환한다.

 

서블릿은 자바의 동적 웹 어플리케이션을 위해 필수적인 개념이지만 웹 서버에 응답을 위해서 출력문을 HTML로 작성해야하는 불편함이 있는데 이것을 해결하기위해 JSP가 개발되었다.

 

 

JSP

Servlet이 자바 코드내에 HTML문서를 포함하는 반면 JSP는 HTML 문서안에 자바코드를 포함한다.

 

JSP를 사용하면 클라이언트의 요청을 JSP 문서 형태로 받아오며 Servlet container에서 해당 JSP문서를 자바언어로 컴파일한다. 이후 서블릿의 동작방식과 동일하게 진행되며 마지막에 응답을 JSP 형태로 다시 변환하여 웹 서버에 보내주게된다.

 

JSP를 사용함으로써 요청과 응답의 처리를 더 독립적으로 분리하여 처리하여 서블릿만을 사용할때보다 더 편리하게 개발이 가능해젔지만 모든 요청과 그에 해당하는 응답에 대한 JSP문서를 만들어 주어야 하는 번거로움이 생겼다. 이를 해결하기 위해 MVC방식을 사용하게 된다.

 

 

Spring Web MVC

Spring Web MVC는 웹 프레임워크의 한 종류로 보통 Spring MVC라 부른다. 

JSP와 같이 MVC 또한 서블릿을 기반으로 사용되며 Model, View, Controller 3단계로 나뉘어 클라이언트의 요청이 처리가 된다. 

 

Model

클라이언트의 요청에 대해 특정한 작업을 진행하여 응답으로 돌려줄 원시형태의 데이터를 Model이라한다. 쉽게말해 비즈니스 로직을 거친 결과물이며 3계층 아키텍처의 서비스 계층(비즈니스 계층)에서 작업이 진행된다.

 

3계층 아키텍처란 클라이언트와 서버간의 상호작용에 대해 단계를 나눠 사용자의 요청과 응답에 대한 처리를 기능적으로 분리하여 구현한다.

3계층 아키텍처

 

View

View는 앞에서 비즈니스로직을 거처 응답을 위해 얻어낸 데이터(Model)를 이용하여 클라이언트 애플리케이션의 화면에 보여지는 리소스(HTML)를 제공하는 역할을 한다.

 

View의 형태

  • HTML 형태 - 클라이언트 서버가아닌 백엔드 서버에서 직접 HTML 형식으로 직접 작성하여 렌더링한뒤 클라이언트 측에 전송하는 방식(Server Side Rendering)
  • PDF, Excel등의 문서 형태 - Model(오리지날 데이터)를 가공하여 필요한 문서 형태로 만들어 클라이언트로 전송하는 방식
  • XML, JSON등 특정 포맷 형태 - 특정 프로토콜 형태로 데이터를 변환시켜 클라이언트에 전송하는 방식, 이후 클라이언트 서버에서 해당 데이터를 기반으로 HTML 페이지를 만든다.(Client Side Rendering)

 

Controller

클라이언트의 요청을 직접적으로 전달 받는 엔드포인트로써 해당 요청에 맞는 비즈니스로직을 찾아주고 이후 나온 Model(결과물)을 View에 전달해주는 등 중간 상호작용을 해주는 역할을 한다.

 

컨트롤러 정의 에노테이션 (클래스에 사용)

  • @Controller - 해당 클래스를 컨트롤러로 정의하며 @Component 에노테이션이 포함되어 Bean으로 등록되며 스프링 컨테이너에서 관리된다.
  • @RestController - Rest API를 위한 컨트롤러로 정의된다. @Controller@ResponseBody 에노테이션이 포함되어 있으며 JSON형태로 응답을 보낼수 있다. (Map 구조 혹은 객체(DTO)를 반환해주면 자동으로 JSON 형태로 응답을 보냄).  

맵핑 에노테이션 

  • @RequestMapping - 컨트롤러로 정의된 클래스에 사용하며 해당클래스의 URL엔드포인트를 지정해준다.
  • @GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping - 컨트롤러로 정의된 클래스의 메서드에 사용되며 해당 HTTP 요청을 처리할 메서드를 지정해주며 @RequestMapping의 URL엔드포인트에 더해 엔드포인트를 추가로 정해줄수 있다.

그외 에노테이션

  • @RequestParam - 메서드의 매개변수에 사용하며 URI의 쿼리문에 접근할 수 있다.
  • @RequestBody - 메서드의 매개변수에 사용하며 클라이언트의 form에 작성된 데이터를 받을 수 있다.
  • @PathVariable - 메서드의 매개변수에 사용되며 맵핑 에노테이션의 엔드포인트를 매개변수로 사용할 수 있다.
// @PathVariable의 예
@GetMapping("/{member-id}")
public String getMember(@PathVariable("member-id") long memberId) {
     System.out.println("# memberId: " + memberId);
     return null;
}

 

Spring MVC의 동작 방식

위에서 언급된 3계층 아키텍처 중 API계층에서 해야할 일을 DispatcherServlet의 주도하에 처리하게된다.

진행순서는 위의 그림과 같다.

 

HandlerAdapter : 컨트롤러 내부의 메서드에 매개변수로 DTO를 등록해주면 JSON형태의 request body를 HandlerAdapter가 해당 DTO 인스턴스로 생성해준다. 이때 DTO는 validation을 통해 해당 request body의 정보가 유효한지 검사하게 되며 유효성을 통과하지 못하면 예외를 발생시킨다.

 

위의 그림은 @Controller 에너테이션을 사용한 경우이며 @RestController는 JSON 형태로 응답이 정해저 있으므로 9번 10번 과정은 생략이된다.

 

 

3계층 아키텍처의 흐름

위의 그림과 같은 내용이지만 컨트롤러이후에 비즈니스계층과 데이터 엑세스계층까지 표현된 자료이다.

파란색 상자Spring MVC 프레임워크에 내장된 기능들이며 보라색상자개발자들이 코드로 구현해내야하는 기능들이다. 초록색상자(View)는 상황에따라 개발자가 개입해야되며 어플리케이션이 CSR방식(JSON으로 응답)일경우 MVC가 알아서 처리해준다.

 

 

DispatcherServlet

DispatcherServlet은 3계층 아키텍처 중 API계층 전면에서 HTTP 프로토콜을 통해 들어오는 모든 요청을 중앙집중식으로 처리하는 프론트 컨트롤러 패턴(Front Controller Pattern)을 사용한다.

 

위에서 MVC서블릿을 기반으로 작동한다고 했는데 Spring MVC에서 사용되는 DispatcherServlet서블릿컨테이너에서 생성하는 커다란 서블릿으로 모든 요청을 이 DispatcherServlet에서 처리하며 이로인해 MVC 이전에는 모든 요청에대한 서블릿객체를 만들어 주어야 했지만 Spring MVC는 각각의 엔드포인트 요청에 대해 컨트롤러와 비즈니스 로직등 꼭 필요한 코드만을 작성해 주면 된다.

 

 

마무리

해당 블로그의 작성을 모두 마치고 우연히 서버 실행단계의 출력물을 보고 작성하게되었다.

 

 

서버의 실행단계에서 출력되는 결과물을 보면 위에 언급한 대부분의 내용들이 담겨있다.

  1. API서버를 가동시키면 서블릿 컨테이너(Tomcat)이 가장 먼저 생성이 된다.
  2. 이후 스프링 컨테이너가 생성되고
  3. 컨트롤러로 등록된 Bean들이 생성이된다. (여기서 서블릿 컨테이너는 Bean들을 사전로딩방식으로 생성하는것을 알수 있다.) 이후 서버가 가동이 된다.
  4. 이렇게 서버 가동이후 처음 요청을보내면 DispatcherServlet이 생성되며
  5. 첫번째 요청에 대한 작업이 모두 마치더라도 DispatcherServlet은 삭제되지 않고 이후의 요청들에도 사용된다.

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

Entity와 Mapper  (0) 2023.04.13
DTO (Data Transfer Object) 과 Validation  (0) 2023.04.12
관점 지향 프로그래밍 (Aspect Oriented Programming, AOP)  (0) 2023.04.09
스프링 컨테이너  (0) 2023.04.05
POJO  (0) 2023.04.03