개발자 준비/Spring

[스프링 핵심 정복] 스프링으로 서블릿(Servlet)을 다룬다는 것

osul_world 2022. 1. 1. 17:18
728x90

스프링으로 서블릿(Servlet)을 다룬다는 것

 

[10분 테코톡] 🐶 코기의 Servlet vs Spring - YouTube

 

글을 시작하기 앞서 해당 영상을 꼭 들어보자.

 

개요

서버는 다양한 Http 요청(Request)과 응답(Response) 외에도 네트워크 연결 등 많은 규칙과 처리해야하는 로직들이 존재한다.

 

서버가 처리해야하는 업무

#network
• 서버 TCP/IP 연결 대기, 소켓 연결
        ↓
#Request Http
• HTTP 요청 메시지를 파싱해서 읽기
• POST 방식, /save URL 인지
• Content-Type 확인
• HTTP 메시지 바디 내용 피싱
  • 메시지 바디에 담긴 데이터를 사용할 수 있게 파싱    
        ↓
#비즈니스 로직 수행
• 저장 프로세스 실행 
• 비즈니스 로직 실행
        ↓
#Resposne Http
• 데이터베이스에 저장 요청
• HTTP 응답 메시지 생성 시작
  • HTTP 시작 라인 생성
  • Header 생성
  • 메시지 바디에 HTML 생성에서 입력 
        ↓
#network
• TCP/IP에 응답 전달, 소켓 종료

 

네트워크 연결 설정부터 HTTP 데이터 파싱, 로직 수행후 응답 HTTP 생성 등 많은 처리가 필요하다.

 

이걸 개발자가 매번 처리하기엔 매우 힘들다. 이런 번거로움을 서블릿이 해결해준다.

 

 

서블릿의 등장

 

서블릿은 ''간단한 메서드 호출' '만으로 웹 요청과 응답을 체계적으로 다룰 수 있게 해주는 자바 기반의 웹 애플리케이션 프로그래밍 기술이다.

 

#network
...
        ↓
#Request Http
...
        ↓
# 비즈니스 로직 수행
• 저장 프로세스 실행 
• 비즈니스 로직 실행
        ↓

#Resposne Http
...   
        ↓
#network
...

서블릿을 지원하는 WAS를 이용하면 나머지 처리를 자동으로 해결할수있기 때문에 개발자가 비즈니스 로직에만 집중하도록 해준다.

 

서블릿이 어떻게 생겼는지 알아보자

 

서블릿은 HttpServlet 상속함으로써 쉽게 만들수있다.

 

필요시 HttpServlet method들을 재정의 할수있다.

 //해당 URL로 요청이 들어오면 이 서블릿을 생성한다.
@WebServlet(name = "myServlet", urlPatterns = "/my") 
public class MyServlet extends HttpServlet { //HttpServlet을 상속한다.
    
    @Override  //서블릿 객체 생성시 실행
    public void init(ServletConfig config) throws ServletException{
        super.init();
    }
   
    @Override //서블릿 객체 소멸시 실행
    public void destroy(){
        super.destroy();
    }
    
    @Override //요청을 받을시 실행
    protected void service(HttpServletRequest request, HttpServletResponse response){ 
		super.service(request,response);
    } 
}

HttpServlet이 제공하는 service method를 살펴보면 아래와 같다.

 

아래 코드는 흐름이 잘 보이도록 수정된 코드이다.

 

실제는 이보다 복잡함

 

img

 

요청에따라 doGet(),doPost() 등 메서드를 실행해 로직을 수행한다.

 

필요시 해당 메서드들을 재정의 함으로써 요청에따라 일련의 로직을 정의 할수있다.

public class MyServlet extens HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOEception {
        PrintWriter writer = request.getWriter();
        writer.println("Hello, do it,if Method type is Get"); //GET으로 요청이 들어왔을때 다음 문구를 출력하도록 설정
    }
}

 

서블릿 동작 과정

 

img

 

  1. 해당 URL로 요청이 들어오면 HTTP Request를 서블릿 컨테이너로 전송한다
  2. HTTP Request를 전달받은 서블릿 컨테이너는 HttpServletRequest, HttpServletResponse객체를 생성한다.
  3. web.xml은 사용자가 요청한 URL을 분석하여 어느 서블릿에 대해 요청을 한 것인지 찾는다
  4. 해당 서블릿에서 service 메소드를 호출한 후 클라이언트의 요청종류 (GET, POST)에 따라 doGet 혹은 doPost를 호출한다.
  5. doGet, doPost 메소드는 동적 페이지를 생성한 후 HttpServletResponse 객체에 응답을 보낸다.
  6. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다

 

서블릿 사용하면 자바 코드를 이용해 요청을 쉽게 처리할수있다.

 

서블릿 특징

서블릿으로 요청을 처리할때 개발자는 아래와 같은 기본 제공 서블릿으로 HTTP 스펙을 매우 편리하게 사용할수있다.

 

• HTTP 요청 정보를 편리하게 사용할 수 있는 HttpServletRequest : getCookies() , getHeader() 등의 HTTP 파싱 메서드들을 제공

 

• HTTP 응답 정보를 편리하게 제공할 수 있는 HttpServletResponse : HTTP 응답 정보를 생성하기위한 메서드 제공

 

HTTP 파싱과 같은 처리를 메서드를 통해 쉽게 다룸으로써 개발자들은 좀더 비즈니스 로직 개발에만 집중할수있다.

 

JAVA의 스레드를 이용하여 동작한다.

MVC 패턴에서의 컨트롤러로 이용된다.

 

서블릿 컨테이너

  • 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 한다.
  • 서블릿을 담고 관리하는 컨테이너
  • 서블릿의 생명주기를 관리한다고 생각하면 이해하기 쉽다.

생성 소멸 관리

• 서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기 관리 #!
• 서블릿 객체는 싱글톤으로 관리 #!
• 고객의 요청이 올 때 마다 계속 객체를 생성하는 것은 비효율
  • 최초 로딩 시점에 서블릿 객체를 미리 만들어두고 재활용
  • 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근
• 공유 변수 사용 주의
• 서블릿 컨테이너 종료시 함께 종료 #!
• JSP도 서블릿으로 변환 되어서 사용 #!
• 동시 요청을 위한 멀티 쓰레드 처리 지원 #!

 

스프링으로 서블릿을 다룬다는것

서블릿을 생성하고 필요한 순간에 호출하고 적절한 시점에 소멸시키는것을 서블릿 컨테이너에게 위임했다.

 

서블릿 동작 과정에서 살펴 보았듯이 요청이 들어오면 서블릿 컨테이너는 각 url 요청에 맞는 서블릿을 찾아 실행한다.

 

img

 

 

그런데 여러 요청을 동시처리해야해서 멀티 쓰레드를 사용하는 경우를 살펴보자

 

서블릿은 쓰레드로 동작하며 컨트롤러라고 서블릿 특징에서 설명했다.

 

img

 

각 요청마다 쓰레드를 하나씩 생성하기엔 서버의 부담이 크다.

 

context switching 비용 및 하드웨어의 한계 등

 

또한 요청마다 처리되는 공통로직들이 매번 중복된다.

 

따라서 요청당 서블릿을 하나하나 지정해주는것은 매우 비효율적이다.

 

스프링은 이런 문제를 프론트 컨트롤러 패턴을 도입해서 해결했다.

 

스프링은 프론트 컨트롤러 패턴을 따른다.

 

Dispatcher Servlet의 등장

 

img

왼: 기존 방식 우: 프론트 컨트롤러 적용

 

기존의 방식이 요청마다 쓰래드를 생성하고 각각 서블릿을 정의하여 사용했다면 스프링은 디스패쳐 서블릿이라는 서블릿 하나만을 정의해서 모든 로직을 처리할수있게 한다.

 

프론트 컨트롤러 패턴

 

디스패쳐 서블릿은 일종의 프론트 컨트롤러이다.

 

img

 

각 클라이언트들은 Front Controller에 요청을 보내고,

Front Controller은 각 요청에 맞는 컨트롤러를 찾아서 호출시킨다.

공통 코드에 대해서는 Front Controller에서 처리하고, 서로 다른 코드들만 각 Controller에서 처리할 수 있도록 한다.

 

디스패쳐 서블릿이 web 요청을 처리하는 과정

 

img

 

디스패쳐 서블릿은 프론트 컨트롤러로써 모든 요청을 받고 다양한 처리 인터페이스들과 상호작용하며 응답을 도출한다.

 

스프링은 이런 프론트 컨트롤러 패턴을 도입하여 설계되었다.

 

img

 

동작 순서

  1. 핸들러 조회: 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
  2. 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.
  3. 핸들러 어댑터 실행: 핸들러 어댑터를 실행한다.
  4. 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.
  5. ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.
  6. viewResolver 호출: 뷰 리졸버를 찾고 실행한다. (view 이름으로부터 사용될 view 객체를 맵핑하는 역할) JSP의 경우: InternalResourceViewResolver 가 자동 등록되고, 사용된다.
  7. View 반환: 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환한다. JSP의 경우 InternalResourceView(JstlView) 를 반환하는데, 내부에 forward() 로직이 있다.
  8. 뷰 렌더링: 반환된 뷰를 통해서 뷰를 렌더링 한다.

 

자칫보면 오히려 다뤄야하는 인터페이스들이 많아진것처럼 보이지만 핸들러(컨트롤러)를 제외한 나머지 뷰 리졸버, 핸들러 매핑 등은 스프링 컨테이너가 알아서 관리해주기때문에 개발자는 핸들러(컨트롤러)로직 개발에만 집중할수있다.

 

스프링 컨테이너

프로그램이 동작하는동안 사용되는 객체들을 프레임워크가 대신 관리하고 보관하기 위해 사용되는 컨테이너

 

@Commponent 즉 서비스,레파지토리,도메인 등의 객체 관리 및 다양한 스프링 빈 관리

 

개발에 필요한 부분을 주입

 

설정 파일만 잘 관리하면 스프링 컨테이너가 알아서 나머지 부분을 관리해준다.

 

 

정리

스프링으로 서블릿을 다룬다는것..

개발자로 하여금 스프링 컨테이너가 제공하는 기능을 활용해서 서블릿을 알아서 관리하도록 하며 개발자는 컨트롤러 즉. 핵심로직 개발에만 집중할수있도록 하기 위함

 

 

Reference

https://www.youtube.com/watch?v=calGCwG_B4Y

https://coding-factory.tistory.com/742

https://kohen.tistory.com/29

 

 

728x90