[Spring 개념] 3. Springboot 동작원리

deannn.Park·2021년 5월 1일
0

Spring 개념

목록 보기
3/4
post-thumbnail

1. 내장 톰캣을 가진다.

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

Socket

  • 네트워크 상에서 동작하는 프로그램 간의 통신의 종착점(Endpoint). 즉, 네트워크에서 데이터를 통신을 할 수 있게 만들어주는 연결부.

  • 소켓은 운영체제에 포함되어 있고, 소켓을 오픈할 때에는 포트번호가 필요하다.

소켓통신

  • 포트 번호를 정해서 소켓 오픈. 한 포트는 중복 안됨. 
  • 한 포트에 붙는 클라이언트는 1개로 제한된다.따라서 처음 소켓 오픈 시 사용되는 소켓은 메인 쓰레드로 연결의 역할만 한다.
  • 메인 쓰레드인 소켓으로 연결이 되면 클라이언트당 하나의 소켓이 오픈된다. 해당 소켓으로 데이터를 주고 받을 수 있다. 소켓 당 쓰레드가 하나씩 존재한다.
  • 쓰레드로 작동되기 때문에 실제로는 아니지만 동시에 여러 클라이언트와 통신하는 것 처럼 보인다.
  • 장점은 계속 연결이 되어있다는 점과 연결되어 있어 클라이언트 식별이 가능하다는 점이다.
  • 단점은 부하가 많이 걸려 느려질 수 있다.

 

HTTP (Hypertext Transfer Protocol)

  • 웹서버와 클라이언트가 사이에서 문자(문서)를 주고받기 위해 사용되는 통신 규법(프로토콜)

HTTP 통신

  • Stateless 방식. 계속 연결되어 있지는 않고, 필요한 정보만 주고받고 연결을 끊는 방식
  • 계속 연결이 되어있는 형식이 아니기 때문에 부하가 많지 않고 하나의 포트로만 통신이 가능하다.
  • 정보가 필요할 때마다 모두 새로 연결되기 때문에 클라이언트 식별이 불가능하다.
  • HTTP 통신은 소켓통신에 기반이 되서 만들어졌다.
  • static한 자원 제공 (정보가 실시간으로 반영되지 않음)

 

웹서버

  • 가지고 있는 파일/문서를 공유할 수 있게 해주는 서버
  • 클라이언트가 서버에 문서를 요청(Request)하면 서버는 해당 문서를 응답(Response)한다.

  • 서버는 클라이언트의 IP를 몰라도 된다.

  • 웹서버는 자바를 이해하지 못함. 따라서 톰캣 사용

톰캣

  • 웹브라우저에서 읽을수 없는 파일의 코드를 컴파일하고 HTML로 덮어씌워 웹서버 돌려주는 역할
  • 클라이언트가 웹브라우저에서 읽지 못하는 코드(html, js, css 제외한)가 담긴 파일을 요청하면 웹서버는 해당 파일을 톰캣에 넘기고 톰캣은 결과물을 다시 웹서버로 넘긴다.

  • 예를 들면 JSP파일에서 자바코드를 컴파일 한 후 다시 웹서버(아파치)에 돌려준다. 그럼 해당 웹서버는 톰캣으로부터 받은 HTML을 Response 해준다.

 

URL (Uniform Resource Locator)

URI (Uniform Resource Indentifier)


2. 서블릿 컨테이너

출처: https://minwan1.github.io/2018/11/21/2018-11-21-jsp-springboot-%EB%8F%99%EC%9E%91%EA%B3%BC%EC%A0%95/

  • 스프링에서는 URL를 통한 자원 접근이 모두 막혀있다. 따라서 URI를 통해서만 자원에 접근이 가능하다.
  • 따라서 특정한 파일 요청을 할 수 없고, 요청시에는 무조건 자바를 거친다.
  • 따라서 모든 Request는 톰캣을 거친 후 Response 된다.

 

  • 톰캣에는 서블릿 컨테이너가 있고, request가 들어오면 해당 request에 대한 스레드가 생성이 되고, 스레드에 대한 서블릿 객체가 생긴다.
  • 서블릿 객체에서 자바 코드를 실행 시키고, 자바 코드에 대한 결과를 response 한다.
  • 스레드를 생성하는 이유는 여러개의 request를 동시 처리하기 위함이다.
  • 서버 성능에 따라 스레드의 개수를 제한하고, 제한한 수를 넘어서면 request가 대기시킨다.
  • 위와 같은 상황에서 서블릿 객체에서 request를 다 처리하여 response 하고 자리가 비면, 스레드를 삭제 후 다시 생성하는 게 아니고 해당 스레드와 서블릿 객체를 재활용한다. 이로 인해 스레드와 서블릿 객체의 삭제, 생성의 과정이 사라지기 때문에 처리 시간이 단축된다.

서블릿 컨테이너 생명주기


3. web.xml

웹서버에 진입을 했을 때 최초로 할 일이 적혀있는 파일

1. ServletContext의 초기 파라미터

  • 초기 파라미터는 한 번 정해지면 어디서든지 사용 가능한 값이다.

2. Session의 유효시간 설정

Session

  • 인증을 통해서 접속하는 방법.
  • 유효시간을 정하게 되면 각 Session을 해당 시간동안만 접속이 가능하다.
  • 정해진 유효시간보다 더 오래 접속하고 싶다면, 재인증을 통해서 갱신하면 된다.

3. Servlet/JSP에 대한 정의

4. Servlet/JSP 매핑

  • 요청한 자원/로케이션/식별자가 어디에 있는지 알려주고 찾아갈 수 있게 도와주는 것.
  • Servlet/JSP 매핑 시 (web.xml에 직접 매핑 or @WebServlet 어노테이션 사용)에 모든 클래스 매핑을 적용하기에는 코드가 너무 복잡해지므로 FrontController 패턴 이용.

5. Mime Type 매핑

  • Mime Type을 식별 한 후 데이터가 필요한 곳으로 매핑하는 거
  • HTTP get방식은 데이터를 가지고 오지 않음. 데이터를 가지고 가기 위해 요청되었기 때문.

MimeType

  • 서버에 들어올 때 가지고 오는 데이터의 타입

6. Welcome File list

  • 요청의 목적이 불명확실할 때에 보내는 곳.

7. Error Pages 처리

  • 에러가 난 페이지를 따로 처리

8. 리스너/필터 처리

  • 필터 : 요청을 거르거나 가지고 있는 데이터를 필터링 하는 역할
  • 리스너 : 주어진 행동에 대해서 그 행동이 일어나는지 감시하는 역할

9. 보안


4. FrontController 패턴

  • 최초 앞단에서 request 요청을 받아서 필요한 클래스에 넘겨준다. web.xml에서 다 정의 하기 힘들기 때문.
  • 이 때 새로운 요청이 생기기 때문에 request와 response가 새롭게 new 될 수 있다. 그래서 아래의 RequestDispatcher가 필요하다.
    • request와 response는 하나씩만 있을 수 있다. 하지만 FrontController에 설정한 데이터가 나타나면 해당 데이터에 대해 새로 request/response가 생기는데, 최초의 request/response에 덮어씌워지므로 기존 request/response를 유지 할 수 있는 방법이 필요. 그것이 RequestDispatcher.
  • resquest : 서버에게 요청한 정보가 들어있는 객체
  • response : request를 토대로 서버에서 응답한 데이터를 담을 객체
  • 웹서버로 요청이 들어오면, 외부에서 웹서버의 자원으로 직접적으로 접근하는것이 막혀있기 때문에 바로 자원에 접근하는 것이 아닌 톰캣으로 향하게 된다.
  • 톰캣이 request와 response를 자동으로 나누어 객체로 만들어준다.

5. RequestDispatcher

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

  • 페이지를 이동할 때 RequestDispatcher를 이용하면 이전 페이지에서의 데이터를 그대로 가져올 수 도 있다.


6. DisplatcherServlet

  • FrontController 패턴을 직접 짜거나 RequestDispatcher를 직접 구현할 필요가 없다. 스프링에는 DispatcherServlet이 있기 때문.

  • DispatcherServlet은 FrontController 패턴 + RequestDispatcher이다.

  • DispatcherServlet이 자동생성되어 질 때 수 많은 객체 생성(IoC)된다. 보통 필터들이고, 해당 필터들은 내가 직접 등록할 수도 있지만 기본적으로 필요한 필터들은 자동 등록 되어진다.


7. 스프링 컨테이너

  • request가 들어오면 톰캣에서 web.xml을 지난 후, ContextLoaderListner를 통해 공통적으로 사용하는 데이터를 띄운 후, DispatchServlet(주소 분배 역할)을 통해 목적지인 class로 가게 된다.

  • ContextLoaderListner는 모든 스레드에서 공통적으로 사용하는 데이터들을 가저갈 수 있게 하는 역할인데, 공통적인 것들을 스레드별로 모두 만들면 낭비되기 때문에 DispatcherServlet 이전에 공통적인 것들은 모두 가져간다. (ex. DB 에 관련된 데이터)

  • root_ApplicationContext 파일(xml, java ...) 은 공통적으로 사용하는 데이터를 띄우고 IoC 컨테이너에서 관리해준다. ContextLoaderListner는 root_ApplicationContext 파일을 통해 공통적으로 사용하는 데이터를 가져간다.

  • DispatchServlet가 주소 분배를 하기 위해서는 컴포넌트 스캔을 해야 하는데, (Springboot 기준) 해당 패키지의 소스폴더에서 자바 파일을 전체 스캔하여 파일에서 필요한 클래스만 메모리에 띄운다. 메모리에 띄워야 request 들어온 것들이 목적지로 찾아갈 수 있다.

  • 필요한 클래스인지 판별하는 방법은 어노테이션을 통해 알게 되는데, 대략 아래의 어노테이션들을 메모리에 띄운다. 필요한 경우, 어노테이션을 만든 후 메모리에 띄울 수 도 있다.

    • @Controller, @RestController, @Configuration, @Repository, @Service, @Component, ...
  • DB는 ContextLoaderListner 단계에서 띄워지고, 이 단계에서는 DispatcherServlet에서 아직 클래스들을 메모리에 띄우지 않았기 때문에 클래스에 접근을 하지 못하지만, 나중에 DispatcherServlet에서 매핑된 클래스에서는 ContextLoaderListner에서 띄워진 DB에 접근이 가능하다.

DispatcherServlet에 의해 생성되어지는 수 많은 객체들은 Application Context에서 관리된다. 이것을 IoC라고 한다.

 

Application Context

  • IoC란 제어의 역전을 의미한다. 개발자가 직접 new를 통해 객체를 생성하게 된다면 해당 객체를 가르키는 레퍼런스 변수를 관리하게 어렵다. 그래서 스프링이 직접 해당 객체를 관리한다. 이 때 우리는 주소를 몰라도 된다. 이유는, 필요할 때 DI하면 되기 때문이다.

  • DI를 의존성 주입 이라고 한다. 필요한 곳에서 ApplicationContext에 접근하여 필요한 객체를 가져올 수 있다. ApplicationContext는 싱글톤으로 관리되기 때문에 어디에서 접근하든 동일한 객체라는 것을 보장해준다.

  • ApplicationContext의 종류에는 두가지가 있는데, root-applicationContext와 selvlet-applicationContext 이다.

 
a. Servlet-applicationContext

  • servlet-applicationContext는 ViewResolver, Intercepter, MultipartResolver 객체를 생성하고 웹과 관련된 어노테이션 Controller, RestController를 스캔한다.
    • 해당 파일은 DispatcherServlet에 의해 실행된다.

b. root-applicationContext

  • root-applicationContext는 해당 어노테이션을 제외한 어노테이션 Service, Repository 등을 스캔하고 DB 관련 객체를 생성한다. 스캔이란 메모리에 로딩하는 것을 뜻한다.

    • 해당 파일은 ContextLoaderListner에 의해 실행된다. ContextLoaderListner를 실행하는 것은 web.xml이기 때문에, root-applicationContext는 servlet-applicationContext보다 먼저 로드된다.
  • servlet-applicationContext에서는 root-applicationContext가 로드한 객체를 참조할 수 있지만 그 반대는 불가능하다. 생성시점의 차이 때문이다.
    출처: https://minwan1.github.io/2018/11/21/2018-11-21-jsp-springboot-%EB%8F%99%EC%9E%91%EA%B3%BC%EC%A0%95

 

Bean Factory

  • 필요한 객체를 Bean Factory에 등록할 수 도 있다. 여기에 등록하면 초기에 메모리에 등록되지 않고 필요할 때 getBean()이라는 메소드를 호출하여 메모리에 로드할 수 있다. 이것 또한 IoC이다. 그리고 DI하여 사용할 수 있다.

  • ApplicationContext와 다른 점은 Bean Factory에 로드되는 객체들을 미리 로드되지 않고 필요할 때 호출하여 로드되기 때문에 lazy-loading이 된다는 점이다.


8. 요청 주소에 따른 적절한 컨티롤로 요청 (Handler Mapping)

참고: https://minwan1.github.io/2017/10/08/2017-10-08-Spring-Container,Servlet-Container/


9. 응답 (Response)

  • response할 때 html 파일을 응답할지 Data를 응답할지를 결정해야 한다.

  • html파일을 응답하게 되면 ViewResolver가 관여하게 된다.

  • ViewResolver는 response 할 때 해당 파일의 위치(prefix)와 확장자(postfix?)를 같이 붙여서 리턴되도록 도와주는 역할이다.

   ex) return "hello"
         => WEB-INF/views/hello.jsp
  • Data를 응답하게 되면 MessageConverter가 작동하는데, 메시지를 컨버팅 할 때 기본 전략은 json이다.

  • Data를 리턴할 때는 메소드에 @ResponseBody 어노테이션을 붙인다. 그럼 리턴값을 File이 아닌 Data로 취급한다.

  • 그리고 리턴값이 객체이면 MessageConverter가 이 객체를 json으로 변환 후 리턴한다.


 

출처 : https://asfirstalways.tistory.com/334

1~4 : 톰캣이 실행 될 때 실행되는 단계
1. web.xml이 읽혀짐.
2. Servlet Container 생성
3. applicationContext(roor-context) 읽혀짐.
4. 3번에 의해서 DB 관련 객체들이 메모리에 로드됨.
5. 사용자에 의해 요청이 들어옴.
6. DispatcherServlet이 생성. 모든 소스파일들을 스캔 후 필요한 클래스들을 메모리에 로드.
7. presentation-layer(servlet-context) 읽어서 FrontController 패턴 설정.
8. FrontController 패턴에 해당하는 요청은 따로 가져와서 필요한 클래스에 매핑하여 보낸 후 response.

profile
컴퓨터 관련 여러 분야 공부중

0개의 댓글