서블릿 개발하기 연재목록

#1 개발환경 구축 (https://opensrc.tistory.com/180?category=475522)

#2 프로잭트 생성 (https://opensrc.tistory.com/181?category=475522)

#3 첫번째 JSP 파일 만들기 (https://opensrc.tistory.com/182?category=475522)

#4 첫번째 서블릿 만들기 (https://opensrc.tistory.com/183?category=475522)

#5 포스트 요청을 처리하는 서블릿 만들기 (https://opensrc.tistory.com/203?category=475522)

#6 GET/POST 요청과 함께 파라메터 전달 하기 (https://opensrc.tistory.com/204?category=475522)

#7 Servlet 들여다 보기 (https://opensrc.tistory.com/206?category=475522)

===========================================================




이제 간단한 JSP 파일을 하나 만들어 보겠습니다.

Project Explorer 에서 WebContent 디렉토리를 마우스 오른쪽 버튼으로 클릭

New > Other 클릭

Web > JSP File 선택 후 [Next >]

File Name 에 index.jsp 입력 후 [Finish] 클릭

body 와 body사이에 hello, world 라고 입력 후 저장 (Alt + S)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
hello, world
</body>
</html>


브라우저에서 첫번째 웹페이지를 확인합니다.

여기까지 잘 오셨다면 절반은 성공하신 겁니다.

시작이 반이라는 옛말에 의하면 말입니다.


심화 : JSP 라이프 사이클

지금 부터 설명하는 부분은 잘 이해가 안가시는 분은 한가지만 기억하고 건너뛰셔도 됩니다.

'JSP 파일은 실제 서버에서 실행되기 전에 Servlet 변환된 후 실행 된다.'

요것 만 이해하면 아래 내용은 건너 뛰셔도 관계 없습니다.


자 이제부터 JSP가 서블릿에서 실행되기 위해 어떤 과정을 거치는지 살펴 보겠습니다.

서버의 설정에 따라 조금 다르지만 일반적으로 JSP 파일을 새로 만들거나 파일의 내용을 수정한 후, 사용자로 부터 해당 JSP로 요청이 들어오면 서블릿 컨테이너가 JSP파일이 변경되는지 감시하고 있다가 새로 생성된 JSP 파일인 경우 해당하는 Servlet의 클래스가 존재 하지 않거나, class 파일의 생성 시간이 JSP파일의 최종 변경된 시간 보다 오래 되었다면 서블릿 컨테이너(WAS)는 JSP를 Servlet 코드로 변환한뒤 .class로 컴파일 하고 메모리로 로딩한 후에 비로서 실행합니다.

진짜 그런지 우리가 만든 JSP 파일을 살펴보도록 하겠습니다.


Server 텝에서 현재 가동하고 있는 서버를 더블클릭

Open launch configuration 클릭

Arguments 텝 클릭

VM arguments 부분에

-Dcatalina.base="..." 에 해당하는 문자열 복사

탐색기 주소창에 붙혀넣기 후 엔터

이후 다음 경로대로 하위 디렉토리를 탐색한다.

work\Catalina\localhost\ROOT\org\apache\jsp

아래 그림처럼 우리가 만든 JSP가 서블릿으로 변환된 java 파일과 그 서블릿이 컴파일된 class 파일 두개가 생성되어 있습니다.


index_jsp.java 파일의 내용을 구경하겠습니다.

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/8.0.36
 * Generated at: 2017-12-25 14:51:46 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map _jspx_dependants;

  private static final java.util.Set _jspx_imports_packages;

  private static final java.util.Set _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
        throws java.io.IOException, javax.servlet.ServletException {

final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("Insert title here\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("hello, world\r\n");
      out.write("\r\n");
      out.write("\r\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

간단한 JSP 코드가 많은 내용이 더해진 채로 변환되어 있습니다.


중요한 부분 몇가지만 확인하면... 

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase

해당 클래스는 org.apache.jasper.runtime.HttpJspBase를 상속 받았다는 것을 알 수 습니다.

HttpJspBase 의 API 문서는 

https://tomcat.apache.org/tomcat-4.0-doc/jasper/docs/api/org/apache/jasper/runtime/HttpJspBase.html

이곳에서 볼 수 있습니다.

HttpJspBase는 javax.servlet.http.HttpServlet 을 상속 받은 서블릿이라는 것을 추측 할 수 있습니다.

소스의 자세한 부분은 본 문서의 범위를 벗어날 수 있으므로 흥미가 있는 분들만 확인하도록 하고

73라인의 _jspService 메서드에 대해서만 간단히 보겠습니다.

(실제 소스에서는 73라인 이지만 SyntaxHighlighter 설정이 잘 못되어 라인넘버가 밀려서 나옵니다.)

_jspService 메서드는 리턴값이 없으며(void)

인자로 javax.servlet.http.HttpServletRequest 와 javax.servlet.http.HttpServletResponse를 받습니다.

그리고 java.io.IOException, javax.servlet.ServletException 을 throws 할 수 있습니다.

하는 일은

response.setContentType("text/html; charset=UTF-8"); 로 페이지 케릭터 셋을 지정하고

pageContext로 부터 PrintWriter out 을 생성하고 out을 통해 hello, workd 를 출력하고 종료합니다.


이것은 http://localhost 라고 호출 하면 web.xml에 기술되어 있는 welcome-file 에 기술되어 있는 파일중 index.jsp가 호출 되어서 tomcat 내부적으로는 index.jsp에 해당하는 index_jsp.java 서블릿이 실행됩니다.

index_jsp.java 에서는 HTTP GET 메서드에 해당하는 _jspService(...) 메서드가 호출 되면서 파라미터로 사용자의 요청을 담은 HttpServletRequest, 사용자에게 응답할  객체인 HttpServletResponse가 전달 되어 실행 되는 것입니다.

소스한번 살펴 보시고 잘 이해가 안가셔도 한가지만 기억하시면 됩니다.

JSP는 그 자체가 실행되는 것이 아니고 서블릿으로 변환 된 후 실행된다는 것!

이것만 잊지 않으시면 됩니다.


다음시간에는 이것을 참고 해서 hello, world 를 출력하는 서블릿을 작성해 보도록 하겠습니다.

+ Recent posts