ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Servlet vs Spring
    우아한테코톡 2022. 1. 15. 22:01

    ===

    https://youtu.be/calGCwG_B4Y

    스프링으로 웹을 다룬다는 것

     

    ===

    처음 웹서버는 클라이언트 요청에 대해서 정적인 페이지로만 응답할 수 있었다

    그래서 웹 서버에 프로그램을 붙여서 동적인 페이지를 생성하기 시작함

    서블릿도 동적인 페이지를 만들기 위해 웹서버에 붙이는 프로그램 중 하나

     

    ===

    예를 들 HTTP 요청과 응답, 원래 훨씬 더 길고 복잡함

     

    만약 개발자들이 요청 텍스트를 직접 해석하고, 처리하고, 다시 아래 응답과 같은 텍스트 형식으로 만들어야 된다면 

    모든 규약을 확인해가며, 긴 텍스트로 들어온 요청을 분석하고, 거기에 맞는 처리를 하고, 처리한 값을 규약에 맞춰서 응답으로 만들어 보내야한다.

     

    ▽결국 텍스트 형태의 HTTP 요청만 받는거구나 그걸로 쿵짝쿵짝 하는거고

     

    ===

    서블릿으로 요청을 처리할 수 있다!

    사진은 서블릿으로 요청을 처리할 때 사용할 수 있는 http servlet request가 제공하는 메소드의 일부

     

    서블릿이 요구하는 구현 규칙을 지켜주면, 앞의 텍스트 형태의 http요청을 메소드를 호출하는 걸로 파싱할 수 있다! 

    http요청 정보를 쉽게 사용할 수 있고 처리결과도 쉽게 응답으로 변환할 수 있다!

     

    ===

    요청을 받아서 내가 처리를 하고 그걸 다시 응답으로 보내는 것

     

    ===

    서블릿의 실제 생김새

    서블릿이 생성되면 init메소드가 호출이되고, 소멸될 땐 destroy메소드가 호출됨

     

    우리가 집중할 부분은 service, 요청을 처리할 때 호출이 되는 메소드

     

    ===

    서비스를 집중해서 보기, 변형버전

     

    결론은

    GET요청이 들어오면 doGet메소드를 호출

    POST요청이 들어오면 doPost 메소드가 호출된다

     

    그럼 우리 개발자들이 해야하는일은 처리하고 싶은 요청 메소드에 해당하는 doXXX 메소드를 찾아서 재정의를 해주는 것

    ===

    서블릿의 예

     

    여기에 서블릿을 처리할 url만 매핑해주면, 그 url로 GET요청이 들어왔을 때

    Response에다가 문자열을 담아서 응답을 하는 것

     

    ===

    ∴ 서블릿으로 요청을 처리하는법 : 서비스 메소드만 재정의해서 처리방법을 지정하기

     

    ===

    서비스 호출 원리와 서블릿 관리 방법

     

    서블릿 컨테이너 라는 친구가 있다

    일단 서블릿을 담고, 관리하는 친구라고 생각하자

     

    사용자 요청이 들어오면, 서블릿 컨테이너는 해당 요청과 매핑된 서블릿을 찾는다

    어떤 서블릿이 어떤 요청과 매핑돼 있는지는 설정파일에 정의돼 있다

    url패턴부터 읽으면 /hello 라는 요청이 들어오면 HelloServlet이라는 서블릿으로 처리를 하겠다라고 읽는 것

    그 다음 HelloServlet은 servlet이라는 패키지 아래 HelloServlet이라는 클래스 파일로 정의돼있다

     

    이런 설정파일을 서블릿 컨테이너가 읽어서 

    ->어떤 요청이 어떤 서블릿이 필요한지를 알게되면

    ->서블릿 인스턴스가 컨테이너에 있는지 확인을 함

    ->존재하면 그걸 사용 ->없으면 생성해서 사용

    ->생성하면 서블릿의 init()이 호출

    ->서블릿 컨테이너에 스레드를 생성하고 미리 만든 HttpServletResponse랑 HttpServletRequest 객체를 인자로 서비스를 호출

    ->service()의 doXXX가 호출되고, 우리가 정의한 요청처리 로직이 수행

    ->생성했던 Response와 Request객체를 소멸시키고 끝

     

    Response와 Request는 생성시키고 소멸시켰는데 Servlet은 생성만 하고 소멸시키는걸 안함,

    Servlet은 싱글톤으로 관리됨, 소멸하지 않고 있다가 다음번 같은 요청이 들어왔을 때 서블릿 컨테이너에 의해 또 호출돼서 사용

     

     

    서블릿 컨테이너는 결국 서블릿의 생명주기를 관리하는 객체

    *생명주기 : 서블릿을 생성하고, 필요한 순간에 호출하고, 적절한 시점에 소멸시키는 것

     

    이걸 개발자가 아니라 서블릿 컨테이너라는 애들한테 위임함

     

    ===

    한 요청을 처리하는 도중에 다른 요청이 들어온다면?

    이땐 멀티스레드로 요청을 처리하게 됨

    여러스레드가 생성이되고,

    그림처럼 스레드당 다른 서블릿이 처리할 수 있고 

    반대로 여러 스레드에서 한 서블릿으로 갈수도

     

     

    스레드를 생성한다는 것 자체가 큰 비용

    다른 스레드로 전환하는 Context Switch가 많은 오버헤드를 일으켜서

    멀티스레드는 조심해서 사용해야한다, 스레드 생성에 제한을 두지 않으면 많은 요청을 처리하기 위해 많은 스레드를 생성하다가 서버의 하드웨어 한계를 넘어버리면 서버가 터질수도

     

    ===

    요청당 서블릿을 정해주는 것에는 비효율적인 부분이 있는데

    관리의 측면 : 멀티스레딩을 다뤄야한다

    개발의 측면 : 핸들러의 공통로직이 매번 중복된다

     

     

    핸들러의 공통로직이 매번 중복이라는 건 :

    카페에서 메뉴마다 담당하는 직원이 있는 것

    매번 1번 3번이 중복되는 것

     

    이걸 개선하면

    전면에서 주문받고 계산하고 포장하는 공통부분을 빼내서 매니저로 두는 것

     

    즉 손님의 요청 같은 앞단에서 처리할 수 있는 일을 전담하는 매니저를 두는 게 프론트 컨트롤러 패턴

     

    ===

    프론트 컨트롤러 패턴

    스프링 MVC도 프론트 컨트롤러 패턴을 따르고, 모든 요청을 받는 전면 컨트롤러 서블릿을 Dispatcher Servlet이라고 부르게 되는 것

     

    서블릿을 하나만 두고 모든 요청을 다 받을 수 있도록 하는 것

     

    이전에 서블릿을 개별적으로 다뤘던 애들은 요청마다 서블릿을 정의하고 요청을 수행할 때마다 매번 스레드 생성

     

    이제는 하나의 서블릿만 정의하고 그 서블릿을 모든 요청을 수행할 수 있도록 하는 전략을 따르는 것

     

    ===

    Dispatcher Servlet이 web 요청을 처리하는 과정

     

    그전에 

    앞의 예시의 이 구조는 전면 매니저가 일이 많이 밀리면 큰일나는 구조다!

     

    전면 매니저가 모든 요청만 처리하되, 계산 담당, 음료 담당 직원, 포장 담당 직원 따로 분리한 형태로 개선한다. 이게 dispatcher servlet의 역할분담과 비슷하다

     

    Dispatcher Servlet : 모든 요청 다 받음

    Handler Mapping : 요청을 처리할 때 컨트롤러를 찾아서 반환

    Handler Adapter : 그 컨트롤러의 메소드를 호출해서 처리 로직 수행

    ▽컨트롤러 찾는애랑, 컨트롤러의 메소드 호출하는애가 나뉘네

     

    그리고 그 처리 결과를 Model And View 객체로 변환해서 Dispatcher Servlet에 넘기고 

     

    다시 Dispatcher Servlet는 View Resolver를 이용해서 뷰를 찾거나 생성 ( 아래에 있는애가 View Resolver 인가봐 )

    그렇게 얻은 View에

     

    아까 모델로 들어왔던 데이터를 넣어서 응답결과 생성을 요청해서 우리가 볼 수 있는 JSP나 Thumeleaf 같은 데이터를 담은 출력 파일로 응답을 하게 되는 것

     

    말이 쉽지 다 인터페이스들이고, 구현체들도 되게 많음

     

    핸들러 매핑만 하더라도 스프링 mvc에서 제공하는 구현체를 확인한것만 4~5개

     

    역할을 분리하고 스프링을 사용하면서 뭔가 일이 더 많아졌나? 아니

    결국 개발자들이 신경을 써야 할 부분은 

    노란색 부분

     

    빨간색으로 표시한 부분의 역할을 하는 객체들은 디스패처서블릿이 스프링 컨테이너로부터 주입을 받아서 사용하고 동작을 한다

     

    서블릿 컨테이너는 서블릿을 담는 바구니

    스프링 컨테이너는 프로그램이 동작하는 동안 사용되는 자바 객체들을 프레임워크가 대신 관리하고 보관하기 위해 사용되는 바구니 ▽이안에 저 빨간것도 있고 내가 만든것도 있고 그런거구나

     

    ===

    좀 더 자세히보면 두개가 있는데

    Servlet WebApplicationContext : 웹 요청 처리 관련 객체들 담김

    Roto WebApplicationContext : 웹 요청처리 관련된 빈 외의 컴포넌트들 = 서비스, 레포지토리 관련 객체들이 관리가 되고 있는 것

     

    그리고 이 컨테이너가

    개발에 필요한 부분이나

    디스패처서블릿이 요청을 처리할 때 필요한 부분을 알아서 주입함

     

    ===

    한마디로 서블릿 설정파일만 잘 작성해주면, 설정대로 생성된 객체가 스프링 컨테이너에서 관리되고, 

    필요한 부분에 주입받아서 디스패처서블릿이 알아서 사용할 수 있게 된다는 것

     

    ===

    들어도 이해가 안가는 부분 :

    꼭 서블릿 웹 어플리케이션 컨텍스트(디스패처서블릿의 요청처리)뿐만 아니라 컨트롤러를 포함하는 어플리케이션 전반적인 개발 안에서도 필요한 부분에서 루트 웹 어플리케이션 컨텍스트(서블릿 컨테이너)를 활용해서 개발할 수 있게 되는 것 : 그냥 생성된건 막 갖다 쓸 수 있다는 건가

     

    ===

    결국 스프링으로 웹 요청을 처리한다는 것은

    스프링 mvc에서 제공하는

    dispatcher servlet과

    웹 요청 처리 관련 구현체들을 사용할 수 있다는 이야기

     

    와 동시에

     

    스프링 컨테이너, 즉 스프링 IoC를 사용해서 개발할 수 있다는 이야기

     

    ===

    최종적인 목적은

    개발자에게 핸들러(우리가 개발할 때 집중해야하는 요청처리로직들)에만 신경을 쓸 수 있도록 하기 위함

    '우아한테코톡' 카테고리의 다른 글

    인증과 인가와 인증의 방법  (0) 2022.01.18
    WAS, Web Server, Web Container  (0) 2022.01.15
Designed by Tistory.