Servlet,Servlet Container,Spring MVC

문딤·2022년 9월 13일
0

Servlet

서블릿 이란?

클라이언트 요청을 처리하고, 그 결과를 다시 클라이언트에게 전송하는 Servlet클래스의 구현 규칙을 지킨 자바 프로그램이다.
이전의 웹 프로그램들은 클라이언트의 요청에 대한 응답으로 만들어진 페이지를 넘겨주었으나, 현재는 동적인 페이지를 가공하기 위해서 웹 서버가 다른 곳에 도움을 요청한 후 가공된 페이지를 넘겨주게 된다.

💨 이때 서블릿을 사용하게 되면 웹 페이지를 동적으로 생성하여 클라이언트에게 반환해 줄 수 있다.

Servlet의 특징

◻ 클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트html을 사용하여 요청에 응답한다.
◻ Java Thread를 이용하여 동작한다.
◻ MVC 패턴에서 Controller로 이용된다.
◻ HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받는다.
◻ UDP보다 처리 속도가 느리다.
◻ HTML 변경 시 Servlet을 재컴파일해야 하는 단점이 있다.

Servlet의 예시

코드

@WebServlet("/main")
public class main extends HttpServlet {
	private static final long serialVersionUID = 1L;
    
    public main() {
        super();
        // TODO Auto-generated constructor stub
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

◻ urlPattern("/main")을 따라서 URL이 호출되면 서블릿 코드가 실행된다.
◻ HttpServletRequest를 통해 http 요청정보를 사용한다.
ex) request.getparameter("")등등
◻ HttpServletResponse를 통해 http 응답정보를 사용할 수 있다.

Servlet의 동작방식

[Servlet의 동작과정]

  1. 사용자(클라이언트)가 URL을 클릭하면 HTTP Request를 Servlet Container로 전송한다.
  2. HttpRequest를 전송받은 Servlet Container는 HttpServletRequest, HttpServletResponse 두 객체를 생성한다.
  3. web.xml은 사용자가 요청한 URL을 분석하여 어느 서블릿에 대한 요청을 하는 것인지 찾는다.(위 예시에서는 helloServlet)
  4. 해당 서블릿에서 SERVICE 메소드를 호출한 후 HTTP Method 인 POST, GET 여부에 따라 doGet()또는 doPost()를 호출한다.
  5. doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse 객체에 응답을 보낸다.
  6. 응답이 끝나면 HttpServletResponse,HttpServletRequest 두 객체를 소멸시킨다.

Servlet의 생명주기

Servlet은 객체를 생성하고 초기화 작업을 거친 후, 요청을 처리한다.
💨 바로 Servlet이 호출되는 것이 아니다.

Servlet의 생명주기

  1. 요청이 오면, Servlet 클래스가 로딩되어 요청에대한 객체를 생성한다.
  2. 서버는 init() 메소드를 호출해서 Servlet을 초기화 한다.
  3. service()메소드를 호출해서 브라우저의 요청을 처리한다.
  4. SERVICE()메소드는 특정 HTTP(POST,GET)요청을 처리하는 메서드(doGet,doPost)를 호출한다.
  5. 서버는 destroy()메소드를 호출해서 Servlet을 제거한다.

+@ 톰캣의 서블릿 관리

◻ Servlet 객체를 생성하고 초기화하는 작업은 비용이 많은 작업이므로, 다음요청에 대비해서 이미 생성된 Servlet 객체는 메모리에 남겨둔다.

◻ 톰캣이 종료되기 전이나 reload 전에 모든 Servlet을 제거한다.

💨 톰캣은 자원을 좀 더 아껴가며 Servlet을 사용한다.

EX) Servlet 구현 및 구동


@WebServlet("/test")
public class LifeCycleServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

    
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init called");
        super.init();
    }
    public void destroy() {
        System.out.println("destroy called");
        super.destroy();
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("service called");
        super.service(request, response);
    }


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doGet 호출");
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doPOST 호출");
		doGet(request, response);
	}

}

위와 같은 HttpServlet을 상속받는 LifeCycleServlet 클래스를 구현하였다.

톰캣에 프로젝트를 등록하고 , 해당 URL 인 http://localhost:8080/dynamicSource/test 를 요청한다.

◻ 생명주기가 맞다면

init메소드를 호출해서 생성된 servlet객체를 초기화
=>
service 메소드를 호출
=>
특정 HTTP 메서드를 타고 System.out.println() 내용을 호출 할 것이다.

init -> service -> do~ 메소드를 호출하였다.

브라우저를 reload해보았다.

톰캣이 이미 만들어진 Servlet객체를 메모리에 남겨둔다고 했으니,
service메소드 => do ~ 메소드를 호출하는것이 맞다.

그 후 3분정도 지났는데

위와 같이 서블릿클래스를 다시 로드하면서 destroy, Servlet을 소멸시켰다.

+@ Web Server

+이건 따로 정리

https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html

ServletContainer

서블릿 컨테이너는 구현되어있는 Servlet 클래스의 규칭에 맞게 서블릿 객체를 생성, 초기화 , 호출, 종료하는 생명주기를 관리한다.

클라이언트의 요청을 받고 응답할 수 있도록 웹 서버와 소캣으로 통신한다.

ex)
Tomcat은 Web Application Server(WAS)중 하나로, Servlet Container 기능을 제공한다.

서블릿 컨테이너의 동작과정

  1. 웹서버가 HTTP 요청을 받습니다.
  2. 웹서버는 요청을 서블릿 컨테이너로 전달합니다.
  3. 서블릿이 컨테이너에 없다면, 서블릿을 동적으로 검색하여 컨테이너의 주소 공간에 로드합니다
  4. 컨테이너가 서블릿의 init() 메소드를 호출하면, 서블릿이 초기화 됩니다(서블릿이 처음 로드됬을 때 한번만 호출됩니다).
  5. 컨테이너가 서블릿의 service() 메소드를 호출하여 HTTP 요청을 처리합니다(예: 요청의 데이터를 읽고, 응답을 만들어냅니다.). 서블릿은 컨테이너 주소에 남아있고, 다른 HTTP 요청들을 처리할 수 있습니다.
  6. 웹서버는 동적으로 생성된 결과를 올바른 위치에 반환합니다.

+@ JVM의 역활은?

서블릿을 사용하는 것은 JVM이 각 요청을 분리된 자바 스레드 내부에서 처리하도록 하는 것.

  • JVM이 해당 요청을 처리한 후에 생성된 결과를 올바른 장소에 동적으로 반환해준다.

+@ WAS VS Web Server

Spring Container

◻ 스프링 컨테이너는 Bean의 생명주기를 관리하며, 추가적인 기능을 제공하는 역활을 한다.
◻ Bean을 관리하기 위해 IOC(Inversion of Control Container)가 이용된다.
◻ IOC 컨테이너를 상속하면서 부가기능을 추가한 것이 ApplicationContext이다.
◻ Spring MVC 역시 Servlet Container가 관리하는 거대한 서블릿이라 생각된다. 그래서 Servlet없이 MVC만 있으면 된다고 하는 것은 비지니스 로직을 Spring을 통해 처리한다는 것이지, Servlet이 필요없는것은 아니다.
◻ 정리하자면 Servlet 컨테이너가 Spring Bean에 접근하려면 Spring container를 거쳐야한다.

ㅁ ApplicationContext를 스프링 컨테이너라 하며, XML또는 어노테이션 기반의 자바 설정 클래스로 만들수 있다.
◻ 스프링 컨테이너는 파라미터로 넘어온 config 파일정보를 이용해서 스프링 빈(자바객체)를 등록한다.
◻ new 연산자 사용, 인터페이스 호출, 객체의 생명주기를 spring container가 대신한다.

DI container + DI config => ApplicationContext

+@ 싱글톤 컨테이너

◻ 스프링 컨테이너는 객체의 인스턴스를 싱글톤으로 관리하기 때문에 싱글톤 컨테이너라고도 한다.
◻ 싱글톤 빈을 미리 로딩해서 그 빈이 필요한 즉시 바로 사용될 수 있도록 해준다.

💨 즉 app은 빈이 생성될때까지 기다릴 필요가 없다.

+@ Bean

Bean은 Spring IoC 컨테이너에 의해 인스턴스화, 조립 및 관리되는 객체이다.

MVC 패턴

◻ Dispatcher Servlet 내부에 서블릿 WebApplicationContext와 Root WebApplicationContext가 동작하는데 얘네 둘이 Spring container에서 동작하는 컨텍스트 들이다.

그렇다면 이 둘을 관리하는 Dispatcher Servlet이 Spring MVC에서 가지는 역활은 무엇일까?

  1. Dispatcher Servlet을 통해 브라우저의 요청을 받는다.
  2. DispatcherServlet은 요청을 어디로 보낼지 판단한다. 이때 HandlerMapping에 요청에 맞는 기능을 선정해서 해당하는 HandlerAdapter객체를 받아온다.
  3. 만약 Controller를 처리할 Handler객체에 적용할 인터셉터가 있다면, 모든 interceptor 객체의 preHandle메소드를 호출한다.
  4. HandlerAdapter 객체를 통해 실제 컨트롤러의 메소드를 실행한 후 ModelAndVIEW를 얻는다.
  5. 만약 해당 controller를 처리할 Handler객체에 적용할 Interceptor가 있다면 모든 Interceptor 객체의 postHandle메소드를 호출한다.
  6. Dispatcher Servlet은 4번 modelAndView를 통해 view name을 viewResolver에 전달하여, 응답에 필요한 view객체를 얻는다.
  7. Dispatcher Servlet은 4번 과정 modelAndView에서 Model을 파라미터로 넘겨서 render메소드를 호출, 페이지 랜더링을 수행한다.
  8. 랜더링된 페이지를 response로 사용자에게 리턴한다.

  1. 배포서술자에 DispatcherServlet 등록한다.
  2. 웹 컨테이너가 뜰때 DispatcherServlet의 전략 빈들이 생성된다.
  3. 실제 사용자의 Request가 들어온다.
  4. 웹 컨테이너는 DispatcherServlet 객체를 생성하고 초기화 한다. (첫 호출시에만)
  5. 웹 컨테이너가 Request, Response 객체를 생성한다.
  6. 웹 컨테이너의 쓰레드 풀에서 쓰레드 하나를 할당하여 DispatcherServlet 실행.
  7. request uri에 알맞은 핸들러(메소드)를 가져온다. (실제 핸들러를 매핑하는 전략은 DispatcherServlet에 주입된 HandlerMapping 구현체에 의해)
  8. 핸들러를 실행시키기 위하여 핸들러 아답터를 가져온다. (핸들러 클래스 타입마다 적용시킬 아답터가 다르므로)
  9. 인터셉터의 preHandle 실행
  10. 실제 컨트롤러 핸들러(메소드) 실행
  11. 인터셉터의 postHandle 실행
  12. 개발자가 설정한 View 에 알맞도록 렌더링을 실행하여 결과를 write
  13. 웹 컨테이너가 response를 보내주고 유저 스레드 반환

참고

https://victorydntmd.tistory.com/154
https://yangbongsoo.gitbook.io/study/servlet_container
https://www.programcreek.com/2013/04/what-is-servlet-container/
https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-client
https://taes-k.github.io/2020/02/16/servlet-container-spring-container/

profile
풀스택개발자가 될래요

0개의 댓글