ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 스프링 부트 동작 원리
    WEB/Spring 2020. 9. 15. 13:06

    1. 내장 톰캣

    톰켓을 따로 설치할 필요 없이 바로 실행가능하다.

     

    소켓 통신

    A와 B가 서로 메세지를 주고 받기 위해서는 OS에서 제공하는 소켓이 필요하다.

    예를들어 A가 5000번 포트번호로 최초의 연결 용도로 소켓을 오픈한다.

    B가 A의 IP주소와 포트번호를 통해 5000번 포트에 연결을 성공하면, 무작위 포트 번호로 새로운 소켓을 만들고, 5000번 포트는 연결이 끊긴다.

    이때 5000번 포트로 다른 사용자의 연결 요청을 계속 받기 위해서 새로운 포트와의 통신을 다중 스레드를 이용한다.

    소켓 통신의 장점은 연결이 끊어지지 않는다는 점, 단점은 그 때문에 연결이 늘어날수록 부하가 크다는 점

     

    HTTP 통신

    HTTP 통신은 요청과 응답이 이루어지면 바로 연결을 끊어버리기 때문에 부하가 적다는 장점이 있지만, 연결을 끊어버리기 때문에 똑같은 사용자도 계속 다른 사람으로 인식한다. 

     

    HTTP 창시 유래

    웹 서버는 갑, 클라이언트는 을라고 생각하자.

    클라이언트에서 자원을 요청하면 웹 서버가 요청을 받아들이고 적절한 응답을 하는 구조이다.

    이때 자원은 static(정적) 자원만 주고 받을 수 있다.

     

    웹 서버에 jsp파일이나 java파일을 요청한다고 가정해보자.

    웹 서버인 아파치는 정적 파일에만 응답을 할 수 있으므로 jsp나 java 파일을 이해하지 못한다.

    이를 해결하기 위해서, 아차피에 `톰캣`을 추가한다.

    자신이 처리할 수 없는 데이터의 요청이 들어오면 이에 대한 제어권을 아파치가 톰캣에게 넘겨준다.

    톰캣은 java코드를 컴파일하고, 컴파일이 끝나면 컴파일 된 데이터를 html 파일로 만들어준다.

    그 다음 변환된 데이터파일을 아파치에게 넘겨주고, 아파치는 넘겨받은 파일을 클라이언트에게 응답한다.

     

    2. 서블릿 컨테이너

    스프링에서는 URL을 통한 접근을 막고 URI를 통한 접근만을 허용한다.

    요청시에 무조건 자바를 거친다! 즉 제어권을 톰캣에게 위임한다! 

     

    서블릿이란 간단하게 java 코드로 웹을 할 수 있도록 하는 것을 이해하면 된다.

    그리고 서블렛 컨테이너는 이러한 서블릿들을 모아놓은 곳이다.

    최초의 요청이 들어오게 되면 톰캣은 스레드를 하나 만들고, 해당 스레드가 하나의 서블릿 객체를 만든다.

    이 서블릿 객체에서 DB 커넥션, 필요한 데이터를 가져오는 등 수많은 작업을 하게된다.

    스레드를 생성하는 이유는 요청이 수백, 수천개가 올 수 있기 때문에 동시 처리를 위해서 요청이 올때마다 스레드를 생성한다. (만약 스레드를 생성하지 않는다면, 하나의 작업을 처리하는동안 다른 요청은 그 작업이 끝날 때까지 대기 해야한다.)

    이때 스레드가 생성될 때, 무한정으로 생성되지 않고 제한 되어있다. (예를들어 20개라고 가정하자)

    그럼 20개까지는 요청이 들어올 때까지 새로운 스레드가 생성되고, 21개부터는 스레드가 더 이상 생성되지 않고 요청은 잠시 대기한다.

    그리고 이 중 작업이 끝나는 스레드가 발생하면, 새로운 요청은 해당 스레드를 재사용하게 된다.

     

    최종적으로 만들어지는 것은 HttpServletRequest 객체와 HttpServletRespone 객체이다. (톰캣이 만든 객체)

     

    ※ 스레드를 무한정으로 만들게되면 성능의 문제가 발생할 수 있다. 따라서 성능 문제가 발생하지 않으면서 최대한의 스레드를 생성하는게 중요!

     

    3. web.xml

    - ServletContext의 초기파라미터

     

     

    - Session의 유효시간 설정

     

     

    - Servlet/JSP에 대한 정의, 매핑

     

     web.xml에서는 자원들의 위치 정보를 가지고 있다. (정의)

    식별자를 통해 요청한 자원의 위치가 어디있는지 알려주고 그쪽으로 이동할 수 있게 도와준다. (매핑)

     

    - Mime Type 매핑

     

    Mime Type이란 '너가 들고올 데이터의 타입이 뭐야?!'

    내가 들고올 데이터가 어떤 타입인지 알려주는 것

     

    - Welcome File List

     

    목적지에 대한 정보가 없는 데이터를 한 곳에 모아 Welcome File List에 모아둔다.

    사용자 설정에 따라 변경될 수 있음

     

    - Error Page 처리

     

    저장된 자원의 위치를 요청하는 것이 아닌 모르는 자원을 요청할 때, 이를 에러 페이지 처리해준다.

     

    - 리스너/필터 설정

     

     

    - 보안

     

    여기에서 Servlet/JSP 매핑시(web.xml에 직접 매핑 or @WebServlet 어노테이션 사용)에 모든 클래스에 매핑을 적용시키기에는 코드가 너무 복잡해지기 때문에 FrontController 패턴을 이용

     

    4. FrontController 패턴

    최초 앞단에서 reqeust 요청을 받을 때, 특정 주소(예를들어 .do)가 들어오면 FrontController 라는 클래스로 보내라고 web.xml에 설정한다.

    URI 혹은 자바 파일을 요청할 때 바로 자원에 접근하지 못하고 톰캣으로 간다.

    톰캣으로 가면 request와 response라는 객체를 자동으로 만들어낸다. (Buffered 가변길이 문자열 형태의 데이터를 객체 형태로 만들어준다.)

    request에는 요청한 사람에 대한 정보가 들어있다. (요청한 사람이 어떠한 데이터를 요청했는지, 어떤 데이터를 들고 들어왔는지 등)

    이러한 정보를 토대로 응답해줄 response 객체를 만든다. 

    이때 web.xml에 servlet/jsp 매핑이 너무 많이 들어있으면 복잡해지기 때문에, 특정 주소는 FrontController로 보내질 수 있게 세팅을 해준다.

    그리고 FrontController에서 한번 더 해당 자원에 접근할 수 있게 request가 발생하고 이에 응답하기 위해 response가 발생한다.

    이때 새로운 request와 response가 발생하기 때문에 기존의 request, response 객체가 새롭게 갱신된다.

    따라서 이러한 재요청이 발생했을 때 기존의 request, response 객체 정보를 덮어쓰는 기법이 필요한데, 이를 위해서 requestDispatcher를 사용한다.

     

    5. RequestDispatcher

    필요한 클래스 요청이 도달했을 때, FrontController에 도착한 request와 response를 그대로 유지시켜준다.

     

    A에서 a.jsp라는 파일을 요청하면 이를 a.html로 변환하여 웹 브라우저에 a.html의 내용을 보여줄 것이다.

    이 때 a.jsp에 대한 request, resposne 객체가 만들어진다.

    만약 이 화면에서 버튼을 클릭했을 때 다음 페이지로 가게 새로운 요청을 한다면 이에 대한 새로운 응답을 해줄 것이다.

    이때 b.html을 웹 브라우저에 보여주면서 b.jsp에 대한 새로운 request, response 객체가 만들어지기 때문에 기존의 객체는 사라지게 된다.

    이를 해결하기 위해서 새로운 요청시, reqeustDispatcher 방식을 이용하면 a.jsp에 있던 객체의 내용을 그대로 사용하면서 새로운 객체의 내용을 덮어쓸 수 있다.

     

    이러한 requestDispatcher를 이용해야만 페이지간 데이터의 이동이 가능하다!!

     

    6. DispatcherServlet

    스프링에서는 FrontController 패턴을 직접 짜거나, ReqeustDispatcher를 직접 구현할 필요가 없다.

    스프링에서는 DispatcherServlet을 제공하는데, 이는 FrontController + RequestDispatcher 개념이다.

    DispatcherServlet이 자동생성되어 질 때, 수많은 객체가 생성(IoC)된다. 

    보통 필터들이며, 해당 필터들은 내가 직접 등록할 수 있고, 기본적으로 필요한 필터들은 자동 등록된다.

     

    DispatcherServlet의 역할은 크게 컴포넌트 스캔, 주소 분배로 나뉜다.

    주소 분배를 하기 위해서는 Object가 메모리에 로딩 되어있는 상태여야 한다.

    따라서 컴포넌트 스캔을 하는데, 스프링 부트에서는 src 폴더 아래에 있는 자바파일들을 올 스캔하여 특정 어노테이션을 확인한다. (스프링에서 미리 특정 어노테이션을 메모리에 올리겠다고 약속함)

    @Controller, @RestController, @Service 등과 같은 어노테이션이 붙은 클래스들은 스프링에 의해 자동으로 메모리에 로딩된다. (IoC)

    해당 어노테이션은 사용자가 직접 만들수 있음 => 아직 허접이기 때문에 나중에!, 어노테이션에 대한 역할을 잘 알자

    이렇게 컴포넌트 스캔을 통해 특정 클래스들을 메모리에 로딩하고, 주소 분배를 할 수 있다.

     

     

    이때 DispatcherServlet에 접근하기 전에 하는 일이 하나 더 있는데 이를 ContextLoaderListener라고 한다.

    DispatcherServlet에 의해 주소가 분배되면서 새로운 스레드가 계속 생성되는데, 이때 DB Connection과 같이 모든 요청이 공통적으로 사용해야하는 일, 모든 스레드가 공통적으로 사용해도 되는 것들은 ContextLoaderListener에 의해 메모리에 로딩된다.

    ContextLoaderListener는 root_ApplicationContext라는 파일을 읽는다.

     

    7. 스프링 컨테이너

    DisptacherServlet에 의해 생성되어지는 수 많은 Object들은 ApplicationContext에서 관리된다. (IoC)

     

    Application Context

     

    개발자가 직접 new를 통해 객체를 생성하게 된다면 해당 객체를 가르키는 레퍼런스 변수를 관리하기 어렵다.

    그래서 스프링에서는 스프링이 객체를 직접 관리한다. 이를 IoC라고 한다.

    이때 우리는 객체의 주소를 알 필요가 없다. (필요할 때마다 DI하면 되기 때문)

     

    DI란 의존성 주입을 의미한다.

    필요한 곳에서 ApplicationContext에 접근하여 필요한 객체를 가져다 쓸 수 있다.

    ApplicationContext가 싱글톤으로 관리되기 때문에 해당 객체는 동일한 객체이다.

     

    - servlet-ApplicationContext

    ViewResolver, Interceptor, MultipartResolver 객체를 생성

    웹과 관련된 어노테이션 Controller, RestController 등을 스캔

    DispatcherServlet에 의해 실행된다.

     

    - root-ApplicationContext

    위의 어노테이션을 제외한 Service, Repository 등을 스캔 (메모리에 로딩)

    DB관련 객체를 생성

    ContextLoaderListener에 의해 실행된다.

     

     

    root-ApplicationContext가 servlet-ApplicationContext보다 먼저 메모리에 로딩되기 때문에, servlet-ApplicationContext에서 root-ApplicationContext가 로드한 객체를 참조할 수 있찌만 그 반대는 불가능하다.

     

    Bean Factory

     

    필요한 객체를 Bean Factory에 등록할 수 있음

    초기에 메모리에 로딩되는 것이 아니라 필요할 때 getBean()이라는 메소드를 통해 메모리에 로딩할 수 있다.

    역시나 IoC와 DI의 개념이 들어간다.

    ApplicationContext와 차이는 Bean Factory의 로딩된 Object들은 미리 로딩되는 것이 아니라 호출에 의해 로딩되어 lazy-loading의 개념을 가진다.

     

    8 Handler Mapping

    GET요청 => http://localhost:8080/post/1

    해당 주쇼 오청이 오면 적절한 컨트롤러의 함수를 찾아서 실행된다.

     

     

    9. 응답

    html 파일을 응답할지, data를 응답할지 결정해야 하는데, html 파일을 응답하면 ViewResolver가 관여하게 된다.

    data를 응답하게 되면 MessageConverter가 작동하게 되는데, 기본으로 JSON 형태이다.

     

     

     

    www.youtube.com/channel/UCVrhnbfe78ODeQglXtT1Elw
     

    데어 프로그래밍

    getinthere@naver.com

    www.youtube.com

    getinthere.tistory.com/11?category=813090
     

    스프링부트 with JPA 3강 - Springboot 동작원리!

    1. 스프링부트 동작원리 (1) 내장 톰켓을 가진다. 톰켓을 따로 설치할 필요 없이 바로 실행가능하다. (2) 서블릿 컨테이너 (3) web.xml -ServletContext의 초기 파라미터 -Session의 유효시간 설정 -Servlet/JSP..

    getinthere.tistory.com

     

    댓글

Designed by Tistory.