SlideShare a Scribd company logo
深入淺出 Web 容器
    Tomcat 原始碼分析
林信良
資深技術顧問
http://openhome.cc
caterpillar@openhome.cc
主題
• Web 容器與 Servlet
• 從 HTTP 請求到 service()
• 在service()的前後
• 從 JSP 到 Servlet
• 自訂標籤處理
Web 容器與 Servlet
Web 容器與 Servlet

容器(Container)…裝水的嗎?


     別鬧了…容器是個 Java 應用程式,
     介於 Servlet 與Web 伺服器之間,我
     管很多事,你不用認識 Web 伺服器,
     你只要認得我!
Web 容器與 Servlet
    管很多事?哪些事啊?




  你沒想過 HTTP 那些麻煩的
  東西是怎麼變成 Java 物件的
  嗎?你以為 Servlet 中的
  Request 與 Response 是怎
  麼來的?
Web 容器與 Servlet
     看起來好像很複雜?


      要了解我的內在確實不容易,
      那…先從簡單的開始好了…
知道一個Servlet是實
作 Servlet 介面嗎?   …..
來個簡化版的…
RequestFacade requestFacade =
if(servlets.get(servletName) == null) {
                      new RequestFacade(request);
     servlet = (Servlet) myClass.newInstance();
      ResponseFacade responseFacade =
     servlets.put(servletName, servlet);
                      new ResponseFacade(response);
     servlet.init(new Config(myClass));
 }
 else {
     servlet = servlets.get(servletName);
 }
 servlet.service(
     (ServletRequest) requestFacade,
     (ServletResponse) responseFacade);

public void destroy() {
    for(Servlet servlet : servlets.values()) {
       servlet.destroy();
    }
}


   至少你要知道init()、
   service()與destroy()…
Web 容器與 Servlet
       你管的就是這些?

        當然更多!不只ServletRequest、
        ServletResponse、
        ServletConfig、Servlet這些…

 對了!這個範例改寫自這邊…
  http://onjava.com/pub/a/onjava/2003/05/14/j
  ava_webserver.html
從 HTTP 請求到 service()
            我實際上很強壯的
            啦….XD
從 HTTP 請求到 service()
     當請求來到時是 Worker Thread 模式
public void run() {
    while (running) {
                                     採用Thread Pool...XD
        // Allocate a new worker thread
        MasterSlaveWorkerThread workerThread = createWorkerThread();
        // Accept the next incoming connection from the server socket
        ...
        Socket socket = acceptSocket();
        workerThread.assign(socket);
    }
    ..
}




                               沒原始碼沒真相...XD
從 HTTP 請求到 service()
接下來快轉一下…來到了Http11Processor…




     我應該說過我負責建立Request與
     Response物件吧…這個類別剖析HTTP
     並設定Request、Response
從 HTTP 請求到 service()
在Http11Processor的process()中,
呼叫 adapter.service()
adapter.service(request, response);


再來的話這邊的request、response會被
org.apache.catalina.connector套
件中的Request、Response包裹起來...


                  WHY?
從 HTTP 請求到 service()
package org.apache.catalina.connector;
public class Request implements HttpServletRequest {
    …
}

package org.apache.catalina.connector;
public class Response implements HttpServletResponse {
    …
}
從 HTTP 請求到 service()
再快轉一下…Request與Response送到容器
ContainerBase,最後來到StandardWrapper…
public class StandardWrapper extends ContainerBase
              implements ServletConfig, Wrapper, NotificationEmitter {



你要注意一下loadServlet()方法…
回憶…
•Servlet第一次被請求時會被載入…
•建立ServletConfig…
•執行init()…
•呼叫service()…
if (classLoader != null) {
            classClass = classLoader.loadClass(actualClass);
        } else {
            classClass = Class.forName(actualClass);
        }
    }
    ...
// Instantiate and initialize an instance of the servlet class
try {
    servlet = (Servlet) classClass.newInstance();
}
...
try {
    …
        servlet.init(facade);
    …
        servlet.service(req, res);
}

facade 參考至實作 ServletConfig 的實例

protected StandardWrapperFacade facade =
       new StandardWrapperFacade(this);
從 HTTP 請求到 service()
    SingleThreadModel 怎麼實現?你
    可以自己找找看…
            喵…好複雜…Orz

已經省略了很多細節了…你可以用這
個流程來研究一些更深入的…XD
在service()的前後
在service()的前後
你知道在Servlet前可以套用Filter
吧!…




      好像是有這麼一回事…XD
實現了Interceptor Filter模式
當我們又來到Servlet…
在service()的前後
• GenericServlet類別
 – 還實作了ServletConfig介面,將容器呼叫
   init()方法時所傳入的ServletConfig實例
   封裝起來
 – service()方法直接標示為abstract而沒有
   任何的實作
• HTTP相關服務流程定義在HttpServlet
  的service()方法
在service()的前後
        protected void service(HttpServletRequest req,
                                    HttpServletResponse resp)
             throws ServletException, IOException {
             String method = req.getMethod(); // 取得請求的方法
             if (method.equals(METHOD_GET)) { // HTTP GET
                        // 略...
                 doGet(req, resp);
                 // 略 ...
             } else if (method.equals(METHOD_HEAD)) { // HTTP HEAD
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                 // 略 ...
    throws ServletException, resp);
                 doHead(req, IOException {
    String protocol if req.getProtocol();
             } else = (method.equals(METHOD_POST)) { // HTTP POST
    String msg = lStrings.getString("http.method_get_not_supported");
                        // 略 ...
    if (protocol.endsWith("1.1")) {
                 doPost(req, resp);
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
             } else if (method.equals(METHOD_PUT)) { // HTTP PUT
    } else {            // 略 ...
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
}
在service()的前後

     這實現了Template Method模式。。。


現在好像談過了幾個模式?Worker
Thread、Interceptor Filter、Template
Method…
在service()的前後
   來談一下Session怎麼建好了…知道
   Session預設用Cookie儲存Session Id
   吧…
               餅乾我知道…
在service()的前後
if (connector.getEmptySessionPath()
     && isRequestedSessionIdFromCookie()) {
   session = manager.createSession(getRequestedSessionId());
} else {
   session = manager.createSession(null);
}



public Session createSession(String sessionId) {
    Session session = createEmptySession()
    session.setNew(true);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setMaxInactiveInterval(this.maxInactiveInterval);
    if (sessionId == null) {
        sessionId = generateSessionId();
    session.setId(sessionId);
    sessionCounter++;
    return (session);
}
在service()的前後
    Servlet 談好久了…要來談一
    下 JSP 嗎? …XD


   你應該看一下org.apache.catalina.
   session.StandardSession,了解
   Session怎麼儲存…好吧!接下來換個口味好
   了…
從 JSP 到 Servlet
            跟你下棋的其實是一
            隻貓…@.@
從 JSP 到 Servlet
     使用JSP不是比較簡單嗎? …

    在我的世界中真正服務的只有Servlet…沒有
    JSP…
從 JSP 到 Servlet
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
<head>
    <title>SimpleJSP</title>
</head>
<body>
    <h1><%= new java.util.Date() %></h1>
</body>
</html>
從 JSP 到 Servlet
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 {
    // 略...
  public void _jspInit() {
     // 略...
  }
  public void _jspDestroy() {
  }
  public void _jspService(HttpServletRequest request,
                           HttpServletResponse response)
         throws java.io.IOException, ServletException {
         // 略...
  }
}
從 JSP 到 Servlet
從 JSP 到 Servlet
public abstract class HttpJspBase extends HttpServlet
                         implements HttpJspPage {
    // 略...
    public final void init(ServletConfig config)
                                    throws ServletException {
        super.init(config);
        jspInit();
        _jspInit();
    }
    // 略...
    public final void destroy() {
        jspDestroy();
        _jspDestroy();
    }
    public final void service(HttpServletRequest request,
                              HttpServletResponse response)
                               throws ServletException, IOException {
        _jspService(request, response);
    }
    // 略...
}
從 JSP 到 Servlet
• 在<%!與%>之間宣告的程式碼,都將轉譯
  為Servlet中的類別成員或方法
• <%與%>之間所包括的內容,將被轉譯為
  Servlet原始碼_jspService()方法中的內
  容
• <%=與%>運算式元素中的運算式,會直接
  轉譯為out物件print()輸出時的指定內
  容
從 JSP 到 Servlet
 • 隱含物件,其實就是_jspService()中的
   區域參考名稱…
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();



                  這麼說Servlet作的到的,JSP
                  都作的到 …
             原則上是…因為都是轉成Servlet…只不過角色
             職責不同…這是另一個故事了…
自訂標籤處理
我討厭義大利
麵...>.<
自訂標籤處理
 聽說使用 JSTL 就不用吃義大利麵 …
 那是新的 HTML 標籤嗎?。。XD

   別傻了...我只處理 Java 的東西…每個標籤
   後面都還是 Java 物件在處理事情。。XD
自訂標籤處理
自訂標籤處理
•   當JSP網頁中包括Simple Tag自訂標籤 ,在轉
    譯之後...
    1. 建立自訂標籤處理器實例。
    2. 呼叫標籤處理器的setJspContext()方法設定
       PageContext實例。
    3. 如果是巢狀標籤中的內層標籤,則還會呼叫標籤處理
       器的setParent()方法,並傳入外層標籤處理器的
       實例。
    4. 設定標籤處理器屬性(例如這邊是呼叫IfTag的
       setTest()方法來設定)。
    5. 呼叫標籤處理器的setJspBody()方法設定
       JspFragment實例。
    6. 呼叫標籤處理器的doTag()方法。
    7. 銷毀標籤處理器實例。
<f:choose>
   <f:when test="${user.valid}">
      <h1>${user.name}登入成功</h1>
   </f:when>
      ..
</f:choose>


cc.openhome.WhenTag _jspx_th_f_005fwhen_005f0 =
                      new cc.openhome.WhenTag();
...
_jspx_th_f_005fwhen_005f0.setJspContext(_jspx_page_context);
_jspx_th_f_005fwhen_005f0.setParent(_jspx_parent);
…
_jspx_th_f_005fwhen_005f0.setTest(…);
_jspx_th_f_005fwhen_005f0.setJspBody(new Helper(…));
_jspx_th_f_005fwhen_005f0.doTag();
…



              這代表用Simple Tag實作標籤時,你的標籤處
              理器不能太肥大…
自訂標籤處理
•   當JSP中遇到TagSupport自訂標籤時
    1. 嘗試從標籤池(Tag Pool)找到可用的標籤物件,如果找到就
       直接使用,如果沒找到就建立新的標籤物件。
    2. 呼叫標籤處理器的setPageContext()方法設定
       PageContext實例。
    3. 如果是巢狀標籤中的內層標籤,則還會呼叫標籤處理器的
       setParent()方法,並傳入外層標籤處理器的實例。
    4. 設定標籤處理器屬性(例如這邊是呼叫IfTag的setTest()方
       法來設定)。
    5. 呼叫標籤處理器的doStartTag()方法,並依不同的傳回值決
       定是否執行本體或呼叫doAfterBody()、doEndTag()方法。
    6. 將標籤處理器實例置入標籤池中以便再度使用。
自訂標籤處理
org.apache.taglibs.standard.tag.rt.core.WhenTag
    _jspx_th_c_005fwhen_005f0 =
       (org.apache.taglibs.standard.tag.rt.core.WhenTag)
          _005fjspx_005ftagPool_005fc_005fwhen_0026_005ftest.get(
             org.apache.taglibs.standard.tag.rt.core.WhenTag.class);
...

_005fjspx_005ftagPool_005fc_005fwhen_0026_005ftest.reuse(
    _jspx_th_c_005fwhen_005f0);




              這代表用TagSupport實作標籤時,必須注意
              是否要重置標籤處理器的狀態。。
              Pool的工作是由org.apache.jasper.
              runtime.TagHandlerPool完成…
自訂標籤處理
public Tag get(Class handlerClass) throws JspException {
    Tag handler = null;
    synchronized( this ) {
        if (current >= 0) {
            handler = handlers[current--];
            return handler;
        }
    }
    try {
        Tag instance = (Tag) handlerClass.newInstance();
        …
}
public void reuse(Tag handler) {
    synchronized( this ) {
        if (current < (handlers.length - 1)) {
            handlers[++current] = handler;
            return;
        }
    }
    …
}
自訂標籤處理
               我記得還有個 Tag File 的東西…


              是啦!不過…Tag File 會被我轉成 Simple
              Tag 的實作…XD

package org.apache.jsp.tag.web;

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

public final class Errors_tag
    extends javax.servlet.jsp.tagext.SimpleTagSupport
    implements org.apache.jasper.runtime.JspSourceDependent {
最後…
我為什麼要了解這麼多細節…



因為我代勞太多事了…你以為有些行為很奇
怪…但其實看一下原始碼就什麼都知道了…
Thanks
林信良 http://openhome.cc
    caterpillar@openhome.cc




                              52

More Related Content

What's hot

SPA를 AWS Amplify에서 Hosting해 본 경험기
SPA를 AWS Amplify에서 Hosting해 본 경험기SPA를 AWS Amplify에서 Hosting해 본 경험기
SPA를 AWS Amplify에서 Hosting해 본 경험기
ChanMin Park
 
Knowledge Sharing : Java Servlet
Knowledge Sharing : Java ServletKnowledge Sharing : Java Servlet
Knowledge Sharing : Java Servlet
Fahmi Jafar
 
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlJava Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Arjun Thakur
 
Ch04 會話管理
Ch04 會話管理Ch04 會話管理
Ch04 會話管理
Justin Lin
 
[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기
[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기
[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기
OKKY
 
Ch06 使用 JSP
Ch06 使用 JSPCh06 使用 JSP
Ch06 使用 JSP
Justin Lin
 
MongoDB and Node.js
MongoDB and Node.jsMongoDB and Node.js
MongoDB and Node.js
Norberto Leite
 
Windows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.com
Windows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.comWindows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.com
Windows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.com
Michael Gough
 
How to Reverse Engineer Web Applications
How to Reverse Engineer Web ApplicationsHow to Reverse Engineer Web Applications
How to Reverse Engineer Web Applications
Jarrod Overson
 
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
Justin Lin
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
Jesus Perez Franco
 
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ BehaviourWAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
Soroush Dalili
 
RxJS 6 新手入門
RxJS 6 新手入門RxJS 6 新手入門
RxJS 6 新手入門
Will Huang
 
Java Entreprise Edition
Java Entreprise EditionJava Entreprise Edition
Java Entreprise Edition
Sabri Bouchlema
 
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
용근 권
 
Java EE vs Spring Framework
Java  EE vs Spring Framework Java  EE vs Spring Framework
Java EE vs Spring Framework
Rohit Kelapure
 
Secure coding practices
Secure coding practicesSecure coding practices
Secure coding practices
Scott Hurrey
 
Instalacion y uso basico de Jenkins
Instalacion y uso basico de JenkinsInstalacion y uso basico de Jenkins
Instalacion y uso basico de Jenkins
Moisés Elías Araya
 
Ch02 撰寫與設定 Servlet
Ch02 撰寫與設定 ServletCh02 撰寫與設定 Servlet
Ch02 撰寫與設定 Servlet
Justin Lin
 
Spring Framework - MVC
Spring Framework - MVCSpring Framework - MVC
Spring Framework - MVC
Dzmitry Naskou
 

What's hot (20)

SPA를 AWS Amplify에서 Hosting해 본 경험기
SPA를 AWS Amplify에서 Hosting해 본 경험기SPA를 AWS Amplify에서 Hosting해 본 경험기
SPA를 AWS Amplify에서 Hosting해 본 경험기
 
Knowledge Sharing : Java Servlet
Knowledge Sharing : Java ServletKnowledge Sharing : Java Servlet
Knowledge Sharing : Java Servlet
 
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlJava Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
 
Ch04 會話管理
Ch04 會話管理Ch04 會話管理
Ch04 會話管理
 
[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기
[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기
[OKKYCON] 정진욱 - 테스트하기 쉬운 코드로 개발하기
 
Ch06 使用 JSP
Ch06 使用 JSPCh06 使用 JSP
Ch06 使用 JSP
 
MongoDB and Node.js
MongoDB and Node.jsMongoDB and Node.js
MongoDB and Node.js
 
Windows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.com
Windows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.comWindows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.com
Windows splunk logging cheat sheet Oct 2016 - MalwareArchaeology.com
 
How to Reverse Engineer Web Applications
How to Reverse Engineer Web ApplicationsHow to Reverse Engineer Web Applications
How to Reverse Engineer Web Applications
 
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
Java SE 8 技術手冊第 14 章 - NIO 與 NIO2
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
 
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ BehaviourWAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
 
RxJS 6 新手入門
RxJS 6 新手入門RxJS 6 新手入門
RxJS 6 新手入門
 
Java Entreprise Edition
Java Entreprise EditionJava Entreprise Edition
Java Entreprise Edition
 
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
KSUG 스프링캠프 2019 발표자료 - "무엇을 테스트할 것인가, 어떻게 테스트할 것인가"
 
Java EE vs Spring Framework
Java  EE vs Spring Framework Java  EE vs Spring Framework
Java EE vs Spring Framework
 
Secure coding practices
Secure coding practicesSecure coding practices
Secure coding practices
 
Instalacion y uso basico de Jenkins
Instalacion y uso basico de JenkinsInstalacion y uso basico de Jenkins
Instalacion y uso basico de Jenkins
 
Ch02 撰寫與設定 Servlet
Ch02 撰寫與設定 ServletCh02 撰寫與設定 Servlet
Ch02 撰寫與設定 Servlet
 
Spring Framework - MVC
Spring Framework - MVCSpring Framework - MVC
Spring Framework - MVC
 

Viewers also liked

讓程式展現樂趣 玩出實驗精神與創造力
讓程式展現樂趣 玩出實驗精神與創造力讓程式展現樂趣 玩出實驗精神與創造力
讓程式展現樂趣 玩出實驗精神與創造力
Justin Lin
 
Java 8 與 retrolambda
Java 8 與 retrolambdaJava 8 與 retrolambda
Java 8 與 retrolambda
Justin Lin
 
Arduino、Web 到 IoT
Arduino、Web 到 IoTArduino、Web 到 IoT
Arduino、Web 到 IoT
Justin Lin
 
OpenSCAD Workshop
OpenSCAD WorkshopOpenSCAD Workshop
OpenSCAD Workshop
Justin Lin
 
3D 之邏輯與美感交會 - OpenSCAD
3D 之邏輯與美感交會 - OpenSCAD3D 之邏輯與美感交會 - OpenSCAD
3D 之邏輯與美感交會 - OpenSCAD
Justin Lin
 
網站系統安全及資料保護設計認知
網站系統安全及資料保護設計認知網站系統安全及資料保護設計認知
網站系統安全及資料保護設計認知
Justin Lin
 

Viewers also liked (6)

讓程式展現樂趣 玩出實驗精神與創造力
讓程式展現樂趣 玩出實驗精神與創造力讓程式展現樂趣 玩出實驗精神與創造力
讓程式展現樂趣 玩出實驗精神與創造力
 
Java 8 與 retrolambda
Java 8 與 retrolambdaJava 8 與 retrolambda
Java 8 與 retrolambda
 
Arduino、Web 到 IoT
Arduino、Web 到 IoTArduino、Web 到 IoT
Arduino、Web 到 IoT
 
OpenSCAD Workshop
OpenSCAD WorkshopOpenSCAD Workshop
OpenSCAD Workshop
 
3D 之邏輯與美感交會 - OpenSCAD
3D 之邏輯與美感交會 - OpenSCAD3D 之邏輯與美感交會 - OpenSCAD
3D 之邏輯與美感交會 - OpenSCAD
 
網站系統安全及資料保護設計認知
網站系統安全及資料保護設計認知網站系統安全及資料保護設計認知
網站系統安全及資料保護設計認知
 

Similar to 深入淺出 Web 容器 - Tomcat 原始碼分析

Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 ServletServlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Justin Lin
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
javatwo2011
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记yiditushe
 
J2ee经典学习笔记
J2ee经典学习笔记J2ee经典学习笔记
J2ee经典学习笔记yiditushe
 
J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识yiditushe
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
keelii
 
高性能并发Web服务器实现核心内幕
高性能并发Web服务器实现核心内幕高性能并发Web服务器实现核心内幕
高性能并发Web服务器实现核心内幕ideawu
 
香港六合彩
香港六合彩香港六合彩
ev2oik
ev2oikev2oik
香港六合彩
香港六合彩香港六合彩
香港六合彩
aaveow
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
jsp基础速成精华讲解
jsp基础速成精华讲解jsp基础速成精华讲解
jsp基础速成精华讲解wensheng wei
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7
javatwo2011
 
Jdbc4 0 规范技术预研
Jdbc4 0 规范技术预研Jdbc4 0 规范技术预研
Jdbc4 0 规范技术预研lorisjand
 
线程编程方面
线程编程方面线程编程方面
线程编程方面yiditushe
 
Jsp面试知识
Jsp面试知识Jsp面试知识
Jsp面试知识yiditushe
 
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
Kuo-Chun Su
 

Similar to 深入淺出 Web 容器 - Tomcat 原始碼分析 (20)

Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 ServletServlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
Servlet & JSP 教學手冊第二版試讀 - 撰寫與設定 Servlet
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记
 
Jsp
JspJsp
Jsp
 
J2ee经典学习笔记
J2ee经典学习笔记J2ee经典学习笔记
J2ee经典学习笔记
 
J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
 
高性能并发Web服务器实现核心内幕
高性能并发Web服务器实现核心内幕高性能并发Web服务器实现核心内幕
高性能并发Web服务器实现核心内幕
 
香港六合彩
香港六合彩香港六合彩
香港六合彩
 
ev2oik
ev2oikev2oik
ev2oik
 
香港六合彩
香港六合彩香港六合彩
香港六合彩
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
jsp基础速成精华讲解
jsp基础速成精华讲解jsp基础速成精华讲解
jsp基础速成精华讲解
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7
 
Jdbc4 0 规范技术预研
Jdbc4 0 规范技术预研Jdbc4 0 规范技术预研
Jdbc4 0 规范技术预研
 
线程编程方面
线程编程方面线程编程方面
线程编程方面
 
Jsp面试知识
Jsp面试知识Jsp面试知识
Jsp面试知识
 
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
 
Exodus2 大局观
Exodus2 大局观Exodus2 大局观
Exodus2 大局观
 

More from Justin Lin

Ch14 簡介 Spring Boot
Ch14 簡介 Spring BootCh14 簡介 Spring Boot
Ch14 簡介 Spring Boot
Justin Lin
 
Ch13 整合 Spring MVC/Security
Ch13 整合 Spring MVC/SecurityCh13 整合 Spring MVC/Security
Ch13 整合 Spring MVC/Security
Justin Lin
 
Ch11 簡介 JavaMail
Ch11 簡介 JavaMailCh11 簡介 JavaMail
Ch11 簡介 JavaMail
Justin Lin
 
Ch10 Web 容器安全管理
Ch10 Web 容器安全管理Ch10 Web 容器安全管理
Ch10 Web 容器安全管理
Justin Lin
 
Ch09 整合資料庫
Ch09 整合資料庫Ch09 整合資料庫
Ch09 整合資料庫
Justin Lin
 
Ch08 自訂標籤
Ch08 自訂標籤Ch08 自訂標籤
Ch08 自訂標籤
Justin Lin
 
Ch07 使用 JSTL
Ch07 使用 JSTLCh07 使用 JSTL
Ch07 使用 JSTL
Justin Lin
 
CH1. 簡介 Web 應用程式
CH1. 簡介 Web 應用程式CH1. 簡介 Web 應用程式
CH1. 簡介 Web 應用程式
Justin Lin
 
14. 進階主題
14. 進階主題14. 進階主題
14. 進階主題
Justin Lin
 
13.並行、平行與非同步
13.並行、平行與非同步13.並行、平行與非同步
13.並行、平行與非同步
Justin Lin
 
12. 除錯、測試與效能
12. 除錯、測試與效能12. 除錯、測試與效能
12. 除錯、測試與效能
Justin Lin
 
11. 常用內建模組
11. 常用內建模組11. 常用內建模組
11. 常用內建模組
Justin Lin
 
10. 資料永續與交換
10. 資料永續與交換10. 資料永續與交換
10. 資料永續與交換
Justin Lin
 
9. 資料結構
9. 資料結構9. 資料結構
9. 資料結構
Justin Lin
 
8. open() 與 io 模組
8. open() 與 io 模組8. open() 與 io 模組
8. open() 與 io 模組
Justin Lin
 
7. 例外處理
7. 例外處理7. 例外處理
7. 例外處理
Justin Lin
 
6. 類別的繼承
6. 類別的繼承6. 類別的繼承
6. 類別的繼承
Justin Lin
 
5. 從模組到類別
5. 從模組到類別5. 從模組到類別
5. 從模組到類別
Justin Lin
 
4. 流程語法與函式
4. 流程語法與函式4. 流程語法與函式
4. 流程語法與函式
Justin Lin
 
3.型態與運算子
3.型態與運算子3.型態與運算子
3.型態與運算子
Justin Lin
 

More from Justin Lin (20)

Ch14 簡介 Spring Boot
Ch14 簡介 Spring BootCh14 簡介 Spring Boot
Ch14 簡介 Spring Boot
 
Ch13 整合 Spring MVC/Security
Ch13 整合 Spring MVC/SecurityCh13 整合 Spring MVC/Security
Ch13 整合 Spring MVC/Security
 
Ch11 簡介 JavaMail
Ch11 簡介 JavaMailCh11 簡介 JavaMail
Ch11 簡介 JavaMail
 
Ch10 Web 容器安全管理
Ch10 Web 容器安全管理Ch10 Web 容器安全管理
Ch10 Web 容器安全管理
 
Ch09 整合資料庫
Ch09 整合資料庫Ch09 整合資料庫
Ch09 整合資料庫
 
Ch08 自訂標籤
Ch08 自訂標籤Ch08 自訂標籤
Ch08 自訂標籤
 
Ch07 使用 JSTL
Ch07 使用 JSTLCh07 使用 JSTL
Ch07 使用 JSTL
 
CH1. 簡介 Web 應用程式
CH1. 簡介 Web 應用程式CH1. 簡介 Web 應用程式
CH1. 簡介 Web 應用程式
 
14. 進階主題
14. 進階主題14. 進階主題
14. 進階主題
 
13.並行、平行與非同步
13.並行、平行與非同步13.並行、平行與非同步
13.並行、平行與非同步
 
12. 除錯、測試與效能
12. 除錯、測試與效能12. 除錯、測試與效能
12. 除錯、測試與效能
 
11. 常用內建模組
11. 常用內建模組11. 常用內建模組
11. 常用內建模組
 
10. 資料永續與交換
10. 資料永續與交換10. 資料永續與交換
10. 資料永續與交換
 
9. 資料結構
9. 資料結構9. 資料結構
9. 資料結構
 
8. open() 與 io 模組
8. open() 與 io 模組8. open() 與 io 模組
8. open() 與 io 模組
 
7. 例外處理
7. 例外處理7. 例外處理
7. 例外處理
 
6. 類別的繼承
6. 類別的繼承6. 類別的繼承
6. 類別的繼承
 
5. 從模組到類別
5. 從模組到類別5. 從模組到類別
5. 從模組到類別
 
4. 流程語法與函式
4. 流程語法與函式4. 流程語法與函式
4. 流程語法與函式
 
3.型態與運算子
3.型態與運算子3.型態與運算子
3.型態與運算子
 

深入淺出 Web 容器 - Tomcat 原始碼分析

  • 1. 深入淺出 Web 容器 Tomcat 原始碼分析 林信良 資深技術顧問 http://openhome.cc caterpillar@openhome.cc
  • 2. 主題 • Web 容器與 Servlet • 從 HTTP 請求到 service() • 在service()的前後 • 從 JSP 到 Servlet • 自訂標籤處理
  • 4. Web 容器與 Servlet 容器(Container)…裝水的嗎? 別鬧了…容器是個 Java 應用程式, 介於 Servlet 與Web 伺服器之間,我 管很多事,你不用認識 Web 伺服器, 你只要認得我!
  • 5. Web 容器與 Servlet 管很多事?哪些事啊? 你沒想過 HTTP 那些麻煩的 東西是怎麼變成 Java 物件的 嗎?你以為 Servlet 中的 Request 與 Response 是怎 麼來的?
  • 6. Web 容器與 Servlet 看起來好像很複雜? 要了解我的內在確實不容易, 那…先從簡單的開始好了…
  • 9. RequestFacade requestFacade = if(servlets.get(servletName) == null) { new RequestFacade(request); servlet = (Servlet) myClass.newInstance(); ResponseFacade responseFacade = servlets.put(servletName, servlet); new ResponseFacade(response); servlet.init(new Config(myClass)); } else { servlet = servlets.get(servletName); } servlet.service( (ServletRequest) requestFacade, (ServletResponse) responseFacade); public void destroy() { for(Servlet servlet : servlets.values()) { servlet.destroy(); } } 至少你要知道init()、 service()與destroy()…
  • 10. Web 容器與 Servlet 你管的就是這些? 當然更多!不只ServletRequest、 ServletResponse、 ServletConfig、Servlet這些… 對了!這個範例改寫自這邊… http://onjava.com/pub/a/onjava/2003/05/14/j ava_webserver.html
  • 11. 從 HTTP 請求到 service() 我實際上很強壯的 啦….XD
  • 12. 從 HTTP 請求到 service() 當請求來到時是 Worker Thread 模式
  • 13. public void run() { while (running) { 採用Thread Pool...XD // Allocate a new worker thread MasterSlaveWorkerThread workerThread = createWorkerThread(); // Accept the next incoming connection from the server socket ... Socket socket = acceptSocket(); workerThread.assign(socket); } .. } 沒原始碼沒真相...XD
  • 14. 從 HTTP 請求到 service() 接下來快轉一下…來到了Http11Processor… 我應該說過我負責建立Request與 Response物件吧…這個類別剖析HTTP 並設定Request、Response
  • 15. 從 HTTP 請求到 service() 在Http11Processor的process()中, 呼叫 adapter.service() adapter.service(request, response); 再來的話這邊的request、response會被 org.apache.catalina.connector套 件中的Request、Response包裹起來... WHY?
  • 16. 從 HTTP 請求到 service() package org.apache.catalina.connector; public class Request implements HttpServletRequest { … } package org.apache.catalina.connector; public class Response implements HttpServletResponse { … }
  • 17. 從 HTTP 請求到 service() 再快轉一下…Request與Response送到容器 ContainerBase,最後來到StandardWrapper… public class StandardWrapper extends ContainerBase implements ServletConfig, Wrapper, NotificationEmitter { 你要注意一下loadServlet()方法… 回憶… •Servlet第一次被請求時會被載入… •建立ServletConfig… •執行init()… •呼叫service()…
  • 18. if (classLoader != null) { classClass = classLoader.loadClass(actualClass); } else { classClass = Class.forName(actualClass); } } ... // Instantiate and initialize an instance of the servlet class try { servlet = (Servlet) classClass.newInstance(); } ... try { … servlet.init(facade); … servlet.service(req, res); } facade 參考至實作 ServletConfig 的實例 protected StandardWrapperFacade facade = new StandardWrapperFacade(this);
  • 19. 從 HTTP 請求到 service() SingleThreadModel 怎麼實現?你 可以自己找找看… 喵…好複雜…Orz 已經省略了很多細節了…你可以用這 個流程來研究一些更深入的…XD
  • 22.
  • 24.
  • 25.
  • 27. 在service()的前後 • GenericServlet類別 – 還實作了ServletConfig介面,將容器呼叫 init()方法時所傳入的ServletConfig實例 封裝起來 – service()方法直接標示為abstract而沒有 任何的實作 • HTTP相關服務流程定義在HttpServlet 的service()方法
  • 28. 在service()的前後 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); // 取得請求的方法 if (method.equals(METHOD_GET)) { // HTTP GET // 略... doGet(req, resp); // 略 ... } else if (method.equals(METHOD_HEAD)) { // HTTP HEAD protected void doGet(HttpServletRequest req, HttpServletResponse resp) // 略 ... throws ServletException, resp); doHead(req, IOException { String protocol if req.getProtocol(); } else = (method.equals(METHOD_POST)) { // HTTP POST String msg = lStrings.getString("http.method_get_not_supported"); // 略 ... if (protocol.endsWith("1.1")) { doPost(req, resp); resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else if (method.equals(METHOD_PUT)) { // HTTP PUT } else { // 略 ... resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } }
  • 29. 在service()的前後 這實現了Template Method模式。。。 現在好像談過了幾個模式?Worker Thread、Interceptor Filter、Template Method…
  • 30. 在service()的前後 來談一下Session怎麼建好了…知道 Session預設用Cookie儲存Session Id 吧… 餅乾我知道…
  • 31. 在service()的前後 if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) { session = manager.createSession(getRequestedSessionId()); } else { session = manager.createSession(null); } public Session createSession(String sessionId) { Session session = createEmptySession() session.setNew(true); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); session.setMaxInactiveInterval(this.maxInactiveInterval); if (sessionId == null) { sessionId = generateSessionId(); session.setId(sessionId); sessionCounter++; return (session); }
  • 32. 在service()的前後 Servlet 談好久了…要來談一 下 JSP 嗎? …XD 你應該看一下org.apache.catalina. session.StandardSession,了解 Session怎麼儲存…好吧!接下來換個口味好 了…
  • 33. 從 JSP 到 Servlet 跟你下棋的其實是一 隻貓…@.@
  • 34. 從 JSP 到 Servlet 使用JSP不是比較簡單嗎? … 在我的世界中真正服務的只有Servlet…沒有 JSP…
  • 35. 從 JSP 到 Servlet <%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <head> <title>SimpleJSP</title> </head> <body> <h1><%= new java.util.Date() %></h1> </body> </html>
  • 36. 從 JSP 到 Servlet 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 { // 略... public void _jspInit() { // 略... } public void _jspDestroy() { } public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { // 略... } }
  • 37. 從 JSP 到 Servlet
  • 38. 從 JSP 到 Servlet public abstract class HttpJspBase extends HttpServlet implements HttpJspPage { // 略... public final void init(ServletConfig config) throws ServletException { super.init(config); jspInit(); _jspInit(); } // 略... public final void destroy() { jspDestroy(); _jspDestroy(); } public final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { _jspService(request, response); } // 略... }
  • 39. 從 JSP 到 Servlet • 在<%!與%>之間宣告的程式碼,都將轉譯 為Servlet中的類別成員或方法 • <%與%>之間所包括的內容,將被轉譯為 Servlet原始碼_jspService()方法中的內 容 • <%=與%>運算式元素中的運算式,會直接 轉譯為out物件print()輸出時的指定內 容
  • 40. 從 JSP 到 Servlet • 隱含物件,其實就是_jspService()中的 區域參考名稱… application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); 這麼說Servlet作的到的,JSP 都作的到 … 原則上是…因為都是轉成Servlet…只不過角色 職責不同…這是另一個故事了…
  • 42. 自訂標籤處理 聽說使用 JSTL 就不用吃義大利麵 … 那是新的 HTML 標籤嗎?。。XD 別傻了...我只處理 Java 的東西…每個標籤 後面都還是 Java 物件在處理事情。。XD
  • 44. 自訂標籤處理 • 當JSP網頁中包括Simple Tag自訂標籤 ,在轉 譯之後... 1. 建立自訂標籤處理器實例。 2. 呼叫標籤處理器的setJspContext()方法設定 PageContext實例。 3. 如果是巢狀標籤中的內層標籤,則還會呼叫標籤處理 器的setParent()方法,並傳入外層標籤處理器的 實例。 4. 設定標籤處理器屬性(例如這邊是呼叫IfTag的 setTest()方法來設定)。 5. 呼叫標籤處理器的setJspBody()方法設定 JspFragment實例。 6. 呼叫標籤處理器的doTag()方法。 7. 銷毀標籤處理器實例。
  • 45. <f:choose> <f:when test="${user.valid}"> <h1>${user.name}登入成功</h1> </f:when> .. </f:choose> cc.openhome.WhenTag _jspx_th_f_005fwhen_005f0 = new cc.openhome.WhenTag(); ... _jspx_th_f_005fwhen_005f0.setJspContext(_jspx_page_context); _jspx_th_f_005fwhen_005f0.setParent(_jspx_parent); … _jspx_th_f_005fwhen_005f0.setTest(…); _jspx_th_f_005fwhen_005f0.setJspBody(new Helper(…)); _jspx_th_f_005fwhen_005f0.doTag(); … 這代表用Simple Tag實作標籤時,你的標籤處 理器不能太肥大…
  • 46.
  • 47. 自訂標籤處理 • 當JSP中遇到TagSupport自訂標籤時 1. 嘗試從標籤池(Tag Pool)找到可用的標籤物件,如果找到就 直接使用,如果沒找到就建立新的標籤物件。 2. 呼叫標籤處理器的setPageContext()方法設定 PageContext實例。 3. 如果是巢狀標籤中的內層標籤,則還會呼叫標籤處理器的 setParent()方法,並傳入外層標籤處理器的實例。 4. 設定標籤處理器屬性(例如這邊是呼叫IfTag的setTest()方 法來設定)。 5. 呼叫標籤處理器的doStartTag()方法,並依不同的傳回值決 定是否執行本體或呼叫doAfterBody()、doEndTag()方法。 6. 將標籤處理器實例置入標籤池中以便再度使用。
  • 48. 自訂標籤處理 org.apache.taglibs.standard.tag.rt.core.WhenTag _jspx_th_c_005fwhen_005f0 = (org.apache.taglibs.standard.tag.rt.core.WhenTag) _005fjspx_005ftagPool_005fc_005fwhen_0026_005ftest.get( org.apache.taglibs.standard.tag.rt.core.WhenTag.class); ... _005fjspx_005ftagPool_005fc_005fwhen_0026_005ftest.reuse( _jspx_th_c_005fwhen_005f0); 這代表用TagSupport實作標籤時,必須注意 是否要重置標籤處理器的狀態。。 Pool的工作是由org.apache.jasper. runtime.TagHandlerPool完成…
  • 49. 自訂標籤處理 public Tag get(Class handlerClass) throws JspException { Tag handler = null; synchronized( this ) { if (current >= 0) { handler = handlers[current--]; return handler; } } try { Tag instance = (Tag) handlerClass.newInstance(); … } public void reuse(Tag handler) { synchronized( this ) { if (current < (handlers.length - 1)) { handlers[++current] = handler; return; } } … }
  • 50. 自訂標籤處理 我記得還有個 Tag File 的東西… 是啦!不過…Tag File 會被我轉成 Simple Tag 的實作…XD package org.apache.jsp.tag.web; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; public final class Errors_tag extends javax.servlet.jsp.tagext.SimpleTagSupport implements org.apache.jasper.runtime.JspSourceDependent {
  • 52. Thanks 林信良 http://openhome.cc caterpillar@openhome.cc 52