서블릿 생명주기와 do method

Byung Seon Kang·2022년 9월 19일
0

서블릿에 대해

목록 보기
2/9
post-thumbnail
  • 이 글은 Head First Servlet & JSP를 기반으로 작성되었습니다.

Servlet LifeCycle

  • 서블릿은 container에 의해 관리된다.
  • life cycle이 어떤식으로 관리되는지 알아보겠음.

우선 요청과 응답에 대한 글은 이전 글을 참고해주세요.
이전 글

  • 요청에 대한 글을 봤다면 다음과 같은 의문이 생길 것이다.
    • 서블릿 클래스는 언제 load 되는가
    • 언제 서블릿의 constructor가 실행되는가
    • 서블릿 object는 얼마나 오래 살아있는가?
      이제 알아봅시다.

State

  • 서블릿의 state는 매우 간단하다.
    • initialized 딱 하나.
  • initialize 되지 않은 상태라면?
    • initialize중이거나 아예 존재하지 않는 상태(init() 또는 constructor 부를때)
    • 또는 destroy되고 있는 상태(running destroy())

Cycle

  • 그럼 이제 state와 연관지어 cycle을 알아보자
  1. Web Container에서 Servlet class를 요청하면, Servlet.class(compile된 서블릿 클래스)를 불러온다.
  2. 서블릿을 인스턴스화한다. 즉, constructor를 호출한다.(아직 존재하지 않는상태)
    • 이때 이 작업이 끝나면 객체로서 존재하게 됨(단, 아직 초기화된 상태 아님)
  3. init()을 호출해서 servlet이 service()를 할 수 있도록 준비시킨다.
    • 생명주기에서 오직 한번만 불림.
    • 이 작업이 끝나면 servlet이 초기화되었다고 할 수 있음.
  4. initialize된 서블릿에 요청이 발생하면 service() 메소드를 호출한다.
    • service()에서는 요청에 맞춰 doPost, doGet등을 실행시켜준다.
  5. destory()를 호출해서 서블릿이 kill될 준비를 시킴.
    • 예를들면 garbage collection을 준비시킨다던가 하는거.
    • init()처럼 한 번만 불린다.

LifeCycle내의 중요한 부분들

1. init()

언제 불리는가?

  • 서블릿 인스턴스가 생성된 이후 호출된다.
  • service()를 호출하기 위해선 반드시 init()과정이 필요하다.
    • 다시말하면, service()는 init()이 호출되기 전에는 호출될 수 없다.

왜 사용하는가?

  • client request를 다루기 위해 필요한 servlet 초기화 과정이 여기서 일어남.

Override를 사용하는가?

  • initialization code(database connection, register with other object...)가 서블릿에 있는 경우 사용한다.

2. service()

언제 불리는가?

  • client request가 들어오면, container는 새로운 thread(혹은 threadpool로부터 기존 thread)를 할당해주고 이후 service() method가 호출됨.

왜 사용하는가

  • request의 HTTP method를 확인한 뒤 적절한 doXXX()(i.e. doGet())를 호출한다.

Override를 사용하는가?

  • 거의 안한다. doGet, doPost등은 거의 무조건 Override한다.

3. doGet(), doPost()...

언제 불리는가?

  • service method가 HTTP method에 따라 doXXX()를 호출하게 됨.

왜 사용하는가

  • 우리가 작성한 코드의 실제 시작점. 즉, 어떤 작업을 수행하는 시작점이다.

Override를 사용하는가?

  • doGet, doPost등은 무조건 적어도 하나이상 Override한다.

간단한 예시

  • ThreadA : init()메소드 호출해서 servlet instance를 생성.
    • init()을 override했으면 작성한 servlet class에서 호출되지만 그렇지 않으면 GenericServlet class에서 호출됨.
  • ThreadB : client의 요청이 들어와서 thread 새로 생성됨. 이후 service() 메소드가 불리고 알맞는 doXXX()호출해서 작업 수행
  • ThreadC: ThreadB와 동일.

각 요청은 다른 thread에서 처리된다!

  • 내가 찾아보면서 가장 헷갈렸던 부분. 책에서 설명 잘해줬다.
  • 각 servlet instance에서 돌아간다고 처음엔 생각했는데 그게 아니었다.
  • servlet instance는 종류별로 하나만 있고, thread를 생성해서 동일한 servlet instance를 활용해 요청을 처리한다.
  • 물론 그렇지 않은 케이스(SingleThreadModel도 있지만 이부분은 특이한 케이스라 제외)

    정리하면, Container는 여러개의 thread를 사용해서 여러개의 request를 처리하는데 이때 사용하는 servlet instance는 오직 하나.

  • 여기서 알아야 할 것.
    • 요청당 하나의 스레드다! 즉, 동일한 유저가 동일한 요청해도 그냥 스레드 생성하던가 다른 스레드 할당.
    • 누가 요청했는지는 별로 신경쓰지 않는다.

Loading과 Initializing에 대해

  • servlet이 life를 시작하는 것은 Container가 servlet class file을 찾을 때이다.
  • 이는 일반적으로 Container가 시작할 때(i.e. tomcat 시작) 발생한다.
    • 왜, 그리고 어디서 servlet을 찾는지는 Deployment 관련 글을 쓰면서 설명하겠음.
  1. Finding class
  2. Loading
    container가 처음 켜질때, 혹은 client가 첫 요청 날렸을 때 실행됨.

일단 이 두 과정 거친 이후 initialization 시작.

Initialization

  • servlet 초기화를 함으로서 Object가 비로소 서블릿의 역할을 할 수 있게 됨.
  • object에서 servlet이 되기 위해서는 특정 권한이 필요하다.
    • ServletContext를 참조해서 Container로부터 정보를 얻는다던가 하는것들.
  • 서블릿이 된다는 것은 무엇을 가지게 되는걸까?
    • ServletConfig object
      • servlet당 하나 가짐
      • database 이름, enterprise bean 이름 등등의 deploy-time information을 전달할 때 사용
      • ServletContext 접근할때도 사용
      • Deployment Descriptor에서 parameter 설정 가능하다.
    • ServletContext
      • web app당 ServletContext 하나
      • web app parameter 접근할 때 사용
      • 메세지를 올리면 application의 다른 파트도 볼 수 있음. 일종의 게시판 역할
      • 서버 정보(이름, 컨테이너 버전, API 버전)등을 볼 수 있다.

추가 잡 얘기

HTTP Method 간단설명

  • HTTP method를 보며 service()에서 doXXX()를 호출한다고 했는데 어떤놈들인지 대충만 보자.
  • Http method는 GET, POST, HEAD, TRACE, PUT, DELETE, OPTIONS, CONNECT가 있다.
    • 여기서 servlet은 doCONNECT()를 지원하지 않는다.

GET과 POST의 차이점

  1. Body의 유무 - POST는 있고 GET은 없다.
    이로인해 GET은 bookmark가 되지만 POST는 안된다.
  2. 멱등성(idempotent)
    GET은 어떤걸 가져온다는 의미지만 POST는 처리할 데이터를 전송한다는 의미 -> 이 의미에 맞춰서 로직 작성해줘야된다
    그럼 다시 생각해보자.
    GET은 동일한 요청을 계속해도 단순히 받아오는거니까 서버에 변경이 없다.
    하지만 POST는 다르다. 요청이 처리되면 서버의 상태가 변화할 수 있다. 예를들어 유저를 계속해서 생성하는 요청을 했다고 하면 새로운 유저가 계속 생성된다.
    요청을 처리해도 변화하지 않는 것을 멱등성(idempotent)이라고 한다.
    즉 POST는 멱등성이 보장되지 않음.
  3. GET은 북마크 가능. POST는 북마크 불가.

JAR 다운로드 받는 코드 예시

	// a bunch of imports here
    public class CodeReturn extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
        										throws IOException, ServletException {
        	response.setContentType("application/jar");
            
            ServletContext ctx = getServletContext();
            InputStream is = ctx.getResourceAsStream("helloWorld.jar");
            
            int read = 0;
            byte[] bytes = new byte[1024];
            
            OutputStream os = response.getOutputStream();
            while ((read = is.read(bytes)) != -1) {
            	os.write(bytes, 0, read);
            }
            os.flush();
            os.close();
        }
    }

Redirect vs Dispatch

  • Redirect : 브라우저한테 딴곳가라고 시키는거
    • sendRedirect() method를 사용한다.
    • sendRedirect() 사용할 때 주의할점이 response stream으로 보내고 난다음에 flush() 하고 사용하면 IllegalStateException 발생한다.
      물론 flush안하고 response 보내게 해서 오류 안나게 할 수도 있지만 매우 안좋은 짓.
  • Dispatch : 서버에서 그냥 딴곳까지 보내주고 일 다 한뒤에 반환해주는거.
    • RequestDispatcher Class 사용
profile
왜 필요한지 질문하기

0개의 댓글