2022-04-11(월)

Jeongyun Heo·2022년 4월 10일
0

스프링 부트가 내부적으로 어떻게 되어 있길래

Spring Boot의 Architecture

91-미니프로젝트3 / 24 페이지

스프링 부트는 내부적으로 Tomcat 서버가 있다

Tomcat 서버 안에는 미니 웹 서버가 있다

미니 웹 서버가 있기에 HTTP 프로토콜에 따라서 요청을 받을 수 있는 거고
HTTP 프로토콜에 따라서 웹 브라우저에 응답할 수 있는 거

메일은 보내는 프로토콜이랑 받는 프로토콜이랑 다르다
보내는 프로토콜 POP
받는 프로토콜 TMAP

웹 서버 = HTTP 서버
HTTP Browser = HTTP 클라이언트

static resource (정적 자원)
정적 자원이면 Web Server가 바로 읽어서 준다. Servlet Container까지 안 감.

static resource가 아니면 Web Server가 Servlet Container에게 위임한다.

HelloController

Servlet Container는 Servlet 인터페이스 규칙에 따라서 만든 클래스만을 실행한다

DispatcherServlet -> Servlet 규칙에 따라서 만들었음
<<Servlet>> DispatcherServlet
DispatcherServlet이 하는 일
클라이언트가 요청한 url을 보고 어떤 클래스의 어떤 메서드를 호출해야 되는지 결정을 내린다
BoardController list()를 호출한다
BoardController가 리턴한다
JSP가 있다면 JSP를 실행한다
JSP를 실행하지 않는다면 다이렉트로 리턴

스프링 부트가 바로 이 부분을 감추고 있는 거
Tomcat 서버와 Spring Web MVC 프레임워크를 포장한 거

Servlet/JSP 기술

Servlet Container와 핵심 구성 요소 (서블릿/JSP, 필터, 리스너)

Servlet Container : Java EE 기술 중에서 Servlet/JSP 기술로 만든 자바 객체를 생성-실행-소멸을 관리하는 서버

Servlet Container ---> 필터 ---> 서블릿/JSP

필터
중간에 개입
call 하기 전
return 하기 전
서블릿 실행 전/후에 추가 작업 수행

리스너 : 특정 상태에 놓일 때 작업을 수행한다
특정 상태? <- 요청이 들어왔을 때, 세션이 생성될 때, 서버가 시작되거나 종료될 때 등
리스너를 만들어서 실행시키면 된다

서블릿 구현 방법과 구동 원리

서블릿 : 클라이언트 요청 처리

Servlet Container ---Servlet 규칙에 따라 호출---> 서블릿

서블릿 객체 존재 -> 서블릿의 service() 호출

서블릿 객체는 오직 한 개 존재한다

서블릿 객체 없음 -> 서블릿 객체 생성 -> 생성자 호출 -> init() 호출 -> service() 호출

<<interface>> Servlet <- 서블릿 컨테이너와 서블릿 사이의 호출 규칙

<<interface>> Servlet
• init() - Servlet의 Lifecycle과 관련된 메서드
• service() - Servlet의 Lifecycle과 관련된 메서드
• destroy() - Servlet의 Lifecycle과 관련된 메서드
• getServletInfo()
• getServletConfig()

서버가 종료되면 생성된 모든 서블릿 객체에 대해 destroy() 호출

• init() : 서블릿 실행에 필요한 자원을 준비한다
• service() : 요청에 대한 작업 처리
• destroy() : init()에서 준비한 자원을 해제시킨다
• getServletInfo() : 관리 기능 수행시 호출됨
• getServletConfig() : 서블릿 실행 중에 설정 정보를 조회할 때 호출됨

@WebServlet("/hello") // 서블릿 컨테이너에게 이 클래스가 /hello 요청을 처리하는 서블릿임을 알려준다.

@WebServlet("/hello")
서블릿 컨테이너에게 이 클래스가 /hello 요청을 처리하는 서블릿임을 알려준다.

/Users/nana/apache-tomcat-9.0.62/bin 로 가기

./startup.sh

http://localhost:8080/web/hello?name=nana

eclipse { } 안에 넣기

// 자바 웹 개발 도구에서 사용할 값을 설정한다.
wtp {
    facet {
        // 웹 애플리케이션을 실행할 컨테이너의 자바 버전을 설정한다.
        facet name: 'jst.java', version: '11'
    }
    facet {
        // 웹 애플리케이션을 실행할 컨테이너의 Servlet/JSP 버전을 설정한다.
        facet name: 'jst.web', version: '4.0'
    }
}

gradle cleanEclipse

gradle eclipse

http://localhost:8080/web/hello

http://localhost:8080/web/index.html

잘 됨

url 입력할 때 web까지 적는 거 귀찮음

        component {
            // 웹 애플리케이션의 컨텍스트 루트 경로를 설정한다.
            // => 즉 이 웹 애플리케이션에 접근할 때 '/'를 사용할 것이라는 의미다.
            contextPath = '/'
        }

gradle cleanEclipse

gradle eclipse

다시 지우고 배치하기

http://localhost:8080/index.html

http://localhost:8080/hello

톰캣 서버 다운 받아서 이클립스에 등록하고 프로젝트 배치하고 너무 귀찮음
그래서 스프링 부트 쓰는 거
지금까지 단계적으로 설정한 거 스프링 부트로 한 번에 한 거

서블릿 객체는 오직 한 개 존재한다
한 개만 생성하기 때문에 init()은 한 번만 호출된다

클라이언트 요청이 들어오면 서블릿이 생성된다

콘솔에서 stop 누르면 destroy 안 보이니까 Server 탭 가서 종료하기

콘솔에서 안 보이면 저걸로 되어 있는지 확인하기

init() : 요청이 들어왔을 때 최초로 서블릿 객체가 존재하지 않으면 객체 생성

해제시킬 자원이 없으면 destroy()는 실행되지 않는다

서블릿을 만드는 방법

91-미니프로젝트3 / 27 페이지

직접 서블릿 구현

<<interface>> Servlet

진짜 중요한 메서드는 service()
service() <- 요청을 처리하는 코드가 들어있다

init(), destroy() <- 준비할 자원이 없으면 필요 없음

근데 인터페이스 메서드는 다 구현해야 됨. 불편함.
GenericServlet이라는 추상클래스가 있음.
init(), destroy(), getServletInfo(), getServletConfig() 기본적으로 구현함. service()만 구현하면 됨.

GenericServlet 상속받아서 service()만 구현한다

public class Hello2Servlet extends GenericServlet {

기존의 서블릿을 수정할 때는 Restart 안 해도 되는데
서블릿을 새로 추가할 때는 서버를 Restart 해야 된다

http://localhost:8080/hello2

근데 현업에서는 다음 방법을 더 많이 쓴다

<<abstract>> HttpServlet 추상 클래스
얘가 미리 service()를 구현했음
오버로딩한 service()를 추가적으로 만들었음
여기서 GET 요청이면

GenericServlet 미리 상속받아서
<<abstract>> HttpServlet
오버로딩한 service() 파라미터가 다름
GET 요청이면 doGet() 메서드 호출하게 프로그램이 짜여있음
POST 요청이면 doPost() 호출하게 프로그램이 짜여있음
HEAD 요청이면 doHEAD()

HttpServlet을 상속받아서 Hello3Servlet을 만든다

GenericServlet + HTTP 프로토콜을 다루는 메서드를 추가함

Hello3Servlet
doGet()을 오버라이딩
doPost()를 오버라이딩

서블릿 컨테이너가 호출하는 건 doPost()가 아니라 service()를 호출한다
service()가 추가한 service()를 호출하고 여기서 내부적으로 doGet(), doPost() 등을 호출한다.
서블릿 컨테이너는 Servlet 인터페이스에 나와 있는 메서드만 호출한다.

doGet() <- GET 요청이 들어왔을 때 호출될 메서드

GET 요청과 POST 요청을 나눠서 처리하고 싶어

서블릿 컨테이너가 호출하는 오리지널 메서드 service()↓

실제 넘어오는 객체는

배식(빵, 음료) {
  ...
}
급식
배식(소보루빵, 우유)

service(ServletRequest req, ServlertResponse res)

실제로는 HttpServletRequest, HttpServletException이 넘어온다

받아서 원래 값으로 형변환 한다
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;

형변환 한 다음에 service()를 호출한다
service(request, response);
HttpServlet 클래스에서 추가한 service()를 호출한다
service(HttpServletRequest req, HttpServletResponse res)
클라이언트가 요청한 방식이 GET이면 doGet()을 호출하도록 프로그래밍되어 있다
HttpServlet를 상속받으면 무조건 doGet(), doPost() 등을 오버라이딩 해야 한다.

HttpServlet를 상속받아서 서블릿을 만드는 방법이 가장 편하다

중요한 건 <<interface>> Servlet 서블릿 인터페이스

http://localhost:8080/hello3

같은 url을 가진 서블릿이 여러 개 존재하면 안 됨

근데 배열은 괜찮음

하나의 서블릿에 url을 여러 개 지정할 수 있다

@WebServlet({"/hello3", "/hello4", "/hello5"})

필터 만드는 방법과 구동 원리

Servlet Container -호출-> 필터 -호출-> 필터 ->

<<interface>> Filter 규칙에 따라 필터를 만든다

필터
서버 시작 -> 객체 생성 -> init() 호출됨
서버 종료 -> destroy()

실제 넘어오는 건 HttpServletRequest 객체인데
HTTP 프로토콜에 한정해서 만든 게 아니었음
웹 분야에서 주로 씀
꼭 웹에서 쓰라고 만든 기술은 아님
웹 쪽에서 많이 쓰고 있음

필터가 먼저 실행되고 서블릿이 실행된다

서블릿이 응답할 때마다 작업을 실행시키고 싶은 게 있으면

서버가 시작할 때 한 번 뭔가 작업을 시키고 싶으면 리스너에 코드를 집어넣으면 된다

0개의 댓글