🌱Backend/Java

#16 Servlet 이해

JiwonDev 2021. 7. 18. 05:28

# μ›Ή 개발의 κ³Όμ •

아무것도 μ—†λŠ” μƒνƒœμ—μ„œ μ›Ή μ„œλ²„λ₯Ό κ΅¬μ„±ν•œλ‹€λŠ” 건, μ•„λž˜μ˜ 과정듀을 μ½”λ“œλ‘œ μž‘μ„±ν•¨μ„ μ˜λ―Έν•œλ‹€. μ΄λŠ” μ–΄λ– ν•œ λ„€νŠΈμ›Œν¬ ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜λ˜ κ³΅ν†΅μ μœΌλ‘œ λ°˜λ³΅λ˜λŠ” κ³Όμ •μ΄μ—ˆλ‹€.

μ •μž‘ μ˜λ―ΈμžˆλŠ” λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ½”λ“œλŠ” μ–Όλ§ˆ λ˜μ§€ μ•Šμ•˜λ‹€.

 


# Java의 Servlet μΈν„°νŽ˜μ΄μŠ€ λ“±μž₯.

'λ„€νŠΈμ›Œν¬ μ½”λ“œμ—μ„œ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ œμ™Έν•œ λ‚˜λ¨Έμ§€λ₯Ό μΈν„°νŽ˜μ΄μŠ€ν™” μ‹œν‚€λ©΄ μ•ˆλ κΉŒ?'μ—μ„œ λ‚˜μ˜¨ 것이 Servlet ν΄λž˜μŠ€μ΄λ‹€.

Server + let, μ„œλ²„μ—μ„œ μ‹€ν–‰ν•˜λŠ” μž‘μ€ μ‹€ν–‰λ‹¨μœ„λΌλŠ” 의미둜 TCP/IP 톡신은 Servlet ν΄λž˜μŠ€κ°€ λ‹΄λ‹Ήν•˜κ³ , λ‚˜λ¨Έμ§€ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 λΆ€λΆ„λ§Œ 직접 κ΅¬ν˜„λ„λ‘ μΈν„°νŽ˜μ΄μŠ€ν™” μ‹œν‚¨ 것이닀. (* Servlet을 μ‹€ν–‰ν•  수 μžˆλŠ” μ›Ή μ„œλ²„λ₯Ό WAS라고 ν•œλ‹€.)

  • html을 μ‚¬μš©ν•˜μ—¬ μš”μ²­μ— μ‘λ‹΅ν•œλ‹€.
  • Java Threadλ₯Ό μ΄μš©ν•˜μ—¬ λ™μž‘ν•œλ‹€.
  • MVC νŒ¨ν„΄μ—μ„œ Controller둜 μ΄μš©λœλ‹€.
  • HTTP ν”„λ‘œν† μ½œ μ„œλΉ„μŠ€λ₯Ό μ§€μ›ν•˜λŠ” javax.servlet.http.HttpServlet 클래슀λ₯Ό μƒμ†λ°›λŠ”λ‹€.
  • UDP보닀 처리 속도가 λŠλ¦¬λ‹€.
  • HTML λ³€κ²½ μ‹œ Servlet을 μž¬μ»΄νŒŒμΌν•΄μ•Ό ν•˜λŠ” λ‹¨μ μ΄ μžˆλ‹€.

HttpServlet을 상속받아 μ„œλΈ”λ¦Ώ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•  수 있으며 HTTP 응닡/전솑을 ν•˜κΈ°μœ„ν•΄ μ„œλΈ”λ¦Ώ μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ œκ³΅ν•˜λŠ” Request와 Response 객체λ₯Ό μ‚¬μš©ν•œλ‹€.

μ–΄λ…Έν…Œμ΄μ…˜(@WebServlet)을 ν™œμš©ν•΄μ„œ μ„œλΈ”λ¦Ώμ„ κ΅¬ν˜„ν•˜λŠ”κ±΄ 비ꡐ적 μ΅œμ‹ μ— λ‚˜μ˜¨ κΈ°λŠ₯이닀.

참고둜 μ„œλΈ”λ¦Ώμ„ μ–΄λ…Έν…Œμ΄μ…˜(@WebServlet)으둜 λ“±λ‘ν•˜λŠ” κΈ°λŠ₯은 Servlet 3 버전(Tomcat 7 이후)에 λ‚˜μ˜¨ κ²ƒμœΌλ‘œ, μ΄μ „μ—λŠ” web.xml νŒŒμΌμ— μ„œλΈ”λ¦Ώμ„ 직접 등둝해주어야 ν–ˆλ‹€. <servlet>으둜 μ„œλΈ”λ¦Ώ 클래슀λ₯Ό λ“±λ‘ν•˜κ³ , <servlet-mapping>으둜 μš”μ²­ URL에 λ‹΄λ‹Ή μ„œλΈ”λ¦Ώμ„ 직접 λ§€ν•‘ν•΄μ£ΌλŠ” 방식이닀.

// web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>JSP_1031</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
  <servlet-name>Hello</servlet-name> //servlet 이름 λͺ…μ‹œ
  <servlet-class>servlet.HelloServlet</servlet-class> //νŒ¨ν‚€μ§€.클래슀 이름을 등둝 ν•΄μ€Œ
  </servlet>
  
  <servlet-mapping>
  <servlet-name>Hello</servlet-name> //servlet의 name을 맀핑
  <url-pattern>/hello</url-pattern>  / κ°€ λ°˜λ“œμ‹œ ν•„μš”!! (μ£Όμ†Œ 뒀에 κ°’μ΄λΌμ„œ)
  </servlet-mapping>
</web-app>

 


# Servlet의 λ™μž‘

μ„œλΈ”λ¦Ώμ€ WAS (μ›Ή μ»¨ν…Œμ΄λ„ˆ, μ„œλΈ”λ¦Ώ μ»¨ν…Œμ΄λ„ˆ)μ—μ„œ λ™μž‘ν•œλ‹€. WAS에 μžˆλŠ” μ›Ή μ»¨ν…Œμ΄λ„ˆλŠ” μ„œλΈ”λ¦Ώμ˜ 생성, 호좜, 관리λ₯Ό λ‹΄λ‹Ήν•œλ‹€.

  1.  Servlet μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ„œ WAS에 등둝해두면, μ›Ή μ„œλ²„λ₯Ό 톡해 ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ„ Servlet 으둜 받을 수 μžˆλ‹€.
    * Servlet은 싱글톀을 κ΅¬ν˜„ν•œλ‹€. 즉 .init() λ©”μ„œλ“œλ‘œ ν•œλ²ˆ λ§Œλ“€μ–΄μ§„ μ„œλΈ”λ¦Ώ κ°μ²΄λŠ” κ³΅μœ ν•΄μ„œ μ—¬λŸ¬ κ³³μ—μ„œ 쓰인닀. .init()λŠ” 처음 ν•œλ²ˆλ§Œ μ‹€ν–‰λœ ν›„ μ„œλΈ”λ¦Ώμ΄ μž¬μ‚¬μš©λœλ‹€. λ§Œμ•½ μ„œλΈ”λ¦Ώ μ½”λ“œκ°€ λ³€κ²½λœλ‹€λ©΄, μ†Œλ©Έμ‹œν‚€κ³  λ‹€μ‹œ init()ν•˜μ—¬ λ§Œλ“ λ‹€.
  2. . μ»¨ν…Œμ΄λ„ˆλŠ” Servlet μš”μ²­μ΄ λ“€μ–΄μ˜€λ©΄ HTTP 응닡 객체(Request,Response)λ₯Ό λ§Œλ“€κ³  μŠ€λ ˆλ“œλ₯Ό ν• λ‹Ήλ°›μ•„ Servlet 클래슀의 .service() λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•œλ‹€.
  3. μ΄λ ‡κ²Œ μŠ€λ ˆλ“œλ₯Ό ν• λ‹Ήλ°›κ³  μ‹€ν–‰λœ Servlet은 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ‹€ν–‰ν•˜κ³  doGet()μ΄λ‚˜ doPost() λ₯Ό ν˜ΈμΆœν•œλ‹€. ν•΄λ‹Ή λ©”μ„œλ“œλŠ” 동적 νŽ˜μ΄μ§€λ₯Ό μƒμ„±ν•˜κ³  Response 객체에 μ‹€μ–΄ μ»¨ν…Œμ΄λ„ˆμ— λ°˜ν™˜ν•œλ‹€.
  4. μ»¨ν…Œμ΄λ„ˆλŠ” 전달받은 Responseλ₯Ό λ‹€μ‹œ HTTP Response둜 λ³€ν™˜ν•˜μ—¬ μ›Ήμ„œλ²„λ₯Ό 톡해 ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 보낸닀. 이후 μŠ€λ ˆλ“œλ₯Ό νšŒμˆ˜ν•˜κ³  ν•„μš”μ—†μ–΄μ§„ 응닡 객체λ₯Ό μ†Œλ©Έμ‹œν‚¨λ‹€. μ„œλΈ”λ¦Ώμ€ μ†Œλ©Έμ‹œν‚€μ§€ μ•Šκ³  μž¬μ‚¬μš©ν•˜λ‹€κ°€ WAS μ„œλ²„κ°€ μ’…λ£Œλ  λ•Œ .destory() λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ μ†Œλ©Έμ‹œν‚¨λ‹€.

@WebServlet("/myServlet/*")
public class MyServlet extends HttpServlet{
    
    private static final long serialVersionUID = 1L;
    String msg = "default";
    
    // The servlet is initialized by calling the init() method.
    public void init() throws ServletException {
        msg = "init λ©”μ†Œλ“œ Call";
    }
    
    // The servlet calls service() method to process a client's request.
    // service () λ©”μ†Œλ“œλŠ” HTTP μš”μ²­ μœ ν˜• (GET, POST, PUT, DELETE λ“±)을 ν™•μΈν•˜κ³  
    // μ μ ˆν•˜κ²Œ doGet, doPost, doPut, doDelete λ“±μ˜ λ©”μ†Œλ“œλ₯Ό 호좜
    @Override
    public void service(ServletRequest request, ServletResponse response) 
            throws ServletException, IOException {
        String text = "Service λ©”μ†Œλ“œ Call";
        if(!"default".equals(msg)){
            text = msg +"<br>"+text;
            msg = "default";
        }
        // response 객체에 헀더값을 κΈ°λ‘ν•œλ‹€.
        response.setContentType("text/plain");  
        response.setCharacterEncoding("UTF-8");
        
        // response 객체에 바디에 넣을 데이터λ₯Ό κΈ°λ‘ν•œλ‹€.
        response.getWriter().write(text);       
    }
    
    
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String text = "doGet λ©”μ†Œλ“œ Call";
        commonMethod(text, response);
    }
    
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String text = "doPost λ©”μ†Œλ“œ Call";
        commonMethod(text, response);
    }
 
    // The servlet is terminated by calling the destroy() method.
    @Override
    public void destroy() {
        // Finalization code...
        System.out.println("destroy method call");
    }
}

 


# WAS와 λ©€ν‹°μŠ€λ ˆλ“œ

기본적으둜 Servlet을 λ§Œλ“€ λ•Œ μ„œλΈ”λ¦Ώ 객체가 싱글톀 κ°μ²΄λΌλŠ”κ±°λ§Œ μœ μ˜ν•˜λ©΄ μ‹±κΈ€μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜λ“―μ΄ νŽΈν•˜κ²Œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ λœλ‹€. κ·Έ μ΄μœ λŠ” WASμ—μ„œ λ©€ν‹° μ“°λ ˆλ“œμ²˜λ¦¬λ₯Ό λŒ€μ‹  ν•΄μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€.

 

μ›Ή μ„œλΉ„μŠ€μ—μ„œλŠ” μ—¬λŸ¬κ°€μ§€ μš”μ²­μ΄ λ™μ‹œμ— λ“€μ–΄ 올 수 μžˆλ‹€. μ΄λ•Œ 단 ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ μ›Ή μ„œλ²„μ˜ μ„±λŠ₯은 맀우 ꡬ질 것이고, λ§Œμ•½ ν•˜λ‚˜μ˜ μš”μ²­μ— 였λ₯˜κ°€ 생긴닀면 λ‹€λ₯Έ μž‘μ—…μœΌλ‘œ λ„˜μ–΄κ°€μ§€ λͺ»ν•΄ μ„œλ²„κ°€ 죽어버릴 것이닀. κ·Έλž˜μ„œ WASμ—λŠ” 기본적으둜 λ©€ν‹°μ“°λ ˆλ“œλ₯Ό μ‚¬μš©ν•œλ‹€.

단일 μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μš”μ²­1을 μ²˜λ¦¬ν•˜λ‹€κ°€ μ§€μ—°λœλ‹€λ©΄, μš”μ²­2도 μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜κ³  μ„œλ²„κ°€ 죽어버린닀.

 

μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  ν• λ‹Ήλ°›λŠ” μž‘μ—…μ€ μš΄μ˜μ²΄μ œμ—μ„œ λ°”λ‘œ λ°›λ˜, μžλ°”μ½”λ“œλ‘œ κ΅¬ν˜„ν•˜λ˜ μ‹œκ°„μ΄ μ˜€λž˜κ±Έλ¦¬λŠ” λΉ„μ‹Ό μž‘μ—…μ΄λ‹€. κ·Έλž˜μ„œ WAS μ„œλ²„μ—λŠ” μ“°λ ˆλ“œ ν’€(pool)을 λ§Œλ“€μ–΄ μ‚¬μš©ν•  μ“°λ ˆλ“œλ₯Ό μ“°λ ˆλ“œ 풀에 미리 μƒμ„±μ‹œμΌœ λ’€λ‹€κ°€, ν•„μš”ν•  λ•Œ μ„œλΈ”λ¦Ώμ— μ“°λ ˆλ“œλ₯Ό ν• λ‹Ήμ‹œμΌœμ€€λ‹€.

λ§Œμ•½ μ“°λ ˆλ“œ 풀에 λ‚¨μ€κ²Œ μ—†λ‹€λ©΄, λŒ€κΈ°ν•˜κ±°λ‚˜ ν•΄λ‹Ή μš”μ²­μ„ 거절(=μš”μ²­ κ±°λΆ€)해버리면 λœλ‹€.

참고둜 WAS μ„œλ²„μ˜ μ£Όμš” μ„±λŠ₯ νŠœλ‹ ν¬μΈνŠΈλŠ” μ΅œλŒ€ μ“°λ ˆλ“œμ˜ κ°œμˆ˜μ— μžˆλ‹€. λ§Œμ•½ 생성가λŠ₯ν•œ μ“°λ ˆλ“œμ˜ μ΅œλŒ€ κ°œμˆ˜κ°€ λ„ˆλ¬΄ 적닀면 μ„œλ²„μ˜ CPU와 λ©”λͺ¨λ¦¬μžμ›μ€ μ—¬μœ λ‘œμš΄λ° μ“°λ ˆλ“œκ°€ λΆ€μ‘±ν•΄ μš”μ²­λ“€μ„ μ²˜λ¦¬ν•˜λŠ”λ° 버벅일 것이닀. λ°˜λŒ€λ‘œ μ΅œλŒ€ μ“°λ ˆλ“œμ˜ 개수λ₯Ό λ¬΄μž‘μ • λ†’κ²Œ μ„€μ •ν•˜λ©΄ CPU, λ©”λͺ¨λ¦¬μ˜ 처리 ν•œκ³„μ μ„ μ΄ˆκ³Όν•˜κ²Œ 되고 μš”μ²­μ΄ 계속 밀리닀가 μ„œλ²„κ°€ 죽어버릴 수 μžˆλ‹€.