tomcat——概述

http://gearever.iteye.comhtml

大致架構java

 

Tomcat由一系列邏輯模塊組織而成,這些模塊主要包括: web

  • 核心架構模塊,例如Server,Service,engine,host和context及wrapper等
  • 網絡接口模塊connector
  • log模塊
  • session管理模塊
  • jasper模塊
  • naming模塊
  • JMX模塊
  • 權限控制模塊

Service中配置了實際工做的Engine,同時配置了用來處理時間業務的線程組Executor(若是沒有配置則用系統默認的WorkThread模式的線程組),以及處理網絡socket的相關組件connector。apache

1) Executor是線程池,它的具體實現是java的concurrent包實現的executor,這個不是必須的,若是沒有配置,則使用自寫的worker thread線程池 
2) Connector是網絡socket相關接口模塊,它包含兩個對象,ProtocolHandler及Adapter 數組

  • ProtocolHandler是接收socket請求,並將其解析成HTTP請求對象,能夠配置成nio模式或者傳統io模式
  • Adapter是處理HTTP請求對象,它就是從StandEngine的valve一直調用到StandWrapper的valve

 

容器類:tomcat提供四種容器,繼承自同一個容器基類,有標準實現,也能夠定製化。tomcat

  • Engine:org.apache.catalina.core.StandardEngine
  • Host: org.apache.catalina.core.StandardHost
  • Context:org.apache.catalina.core.StandardContext
  • Wrapper:org.apache.catalina.core.StandardWrapper

engine

  • Cluster: 實現tomcat集羣,例如session共享等功能,經過配置server.xml能夠實現,對其包含的全部host裏的應用有效,該模塊是可選的。其實現方式是基於pipeline+valve模式的,有時間會專門整理一個pipeline+valve模式應用系列(這篇文章非原創,原做者會整理);
  • Realm:實現用戶權限管理模塊,例如用戶登陸,訪問控制等,經過經過配置server.xml能夠實現,對其包含的全部host裏的應用有效,該模塊是可選的;
  • Pipeline:這裏簡單介紹下,以後會有專門文檔說明。每一個容器對象都有一個pipeline,它不是經過server.xml配置產生的,是必須有的。它就是容器對象實現邏輯操做的骨架,在pipeline上配置不一樣的valve,當須要調用此容器實現邏輯時,就會按照順序將此pipeline上的全部valve調用一遍,這裏能夠參考責任鏈模式;
  • Valve:實現具體業務邏輯單元。能夠定製化valve(實現特定接口),而後配置在server.xml裏。對其包含的全部host裏的應用有效。定製化的valve是可選的,可是每一個容器有一個缺省的valve,例如engine的StandardEngineValve,是在StandardEngine裏自帶的,它主要實現了對其子host對象的StandardHostValve的調用,以此類推。

配置例子安全

<Engine name="Catalina" defaultHost="localhost">     
  <Valve className="MyValve0"/>     
  <Valve className="MyValve1"/>     
  <Valve className="MyValve2"/>     
  ……     
  <Host name="localhost" appBase="webapps">   
  </Host>  
</Engine>

運行環境中,pipeline上的valve數組按照配置的順序加載,可是不管有無配置定製化的valve或有多少定製化的valve,每一個容器缺省的valve,例如engine的StandardEngineValve,都會在數組中最後一個。 服務器

host

StandardHost的核心模塊與StandardEngine差很少。只是做用域不同,它的模塊只對其包含的子context有效。除此,還有一些特殊的邏輯,例如context的部署。Context的部署仍是比較多的,主要分爲:網絡

  • War部署
  • 文件夾部署
  • 配置部署等

Context
Context是host的子容器,它是wrapper容器的集合。

應該說StandardContext是tomcat中最大的一個類。它封裝的是每一個web app。
看一下StandardContext的主要邏輯單元概念圖。session

  • Manager: 它主要是應用的session管理模塊。其主要功能是session的建立,session的維護,session的持久化(persistence),以及跨context的session的管理等。Manager模塊能夠定製化,tomcat也給出了一個標準實現;

          org.apache.catalina.session.StandardManager  


manager模塊是必需要有的,能夠在server.xml中配置,若是沒有配置的話,會在程序裏生成一個manager對象。

  • Resources: 它是每一個web app對應的部署結構的封裝,好比,有的app是tomcat的webapps目錄下的某個子目錄或是在context節點配置的其餘目錄,或者是war文件部署的結構等。它對於每一個web app是必須的。
  • Loader:它是對每一個web app的自有的classloader的封裝。具體內容涉及到tomcat的classloader體系,會在一篇文檔中單獨說明。Tomcat正是有一套完整的classloader體系,才能保證每一個web app或是獨立運營,或是共享某些對象等等。它對於每一個web app是必須的。
  • Mapper:它封裝了請求資源URI與每一個相對應的處理wrapper容器的映射關係。

app>web.xml:

<servlet>  
  <servlet-name>httpserver</servlet-name>  
  <servlet-class>com.gearever.servlet.TestServlet</servlet-class>  
</servlet>  
   
<servlet-mapping>  
  <servlet-name>httpserver</servlet-name>  
  <url-pattern>/*.do</url-pattern>  
</servlet-mapping>

對於mapper對象,能夠抽象的理解成一個map結構,其key是某個訪問資源,例如/*.do,那麼其value就是封裝了處理這個資源TestServlet的某個wrapper對象。當訪問/*.do資源時,TestServlet就會在mapper對象中定位到。這裏須要特別說明的是,經過這個mapper對象定位特定的wrapper對象的方式,只有一種狀況,那就是在servlet或jsp中經過forward方式訪問資源時用到。例如,

request.getRequestDispatcher(url).forward(request, response)  

關於mapper機制會在一篇文檔中專門說明,這裏簡單介紹一下,方便理解。如圖所示。

Mapper對象在tomcat中存在於兩個地方(注意,不是說只有兩個mapper對象存在),其一,是每一個context容器對象中,它只記錄了此context內部的訪問資源與相對應的wrapper子容器的映射;其二,是connector模塊中,這是tomcat全局的變量,它記錄了一個完整的映射對應關係,即根據訪問的完整URL如何定位到哪一個host下的哪一個context的哪一個wrapper容器。
這樣,經過上面說的forward方式訪問資源會用到第一種mapper,除此以外,其餘的任何方式,都是經過第二種方式的mapper定位到wrapper來處理的。也就是說,forward是服務器內部的重定向,不須要通過網絡接口,所以只須要經過內存中的處理就能完成。這也就是常說的forward與sendRedirect方式重定向區別的根本所在。
看一下request.getRequestDispatcher(url) 方法的源碼。

Request
    /**
     * @return a RequestDispatcher that wraps the resource at the specified
     * path, which may be interpreted as relative to the current request path.
     *
     * @param path Path of the resource to be wrapped
     */
    @Override
    public RequestDispatcher getRequestDispatcher(String path) {

        Context context = getContext();
        if (context == null) {
            return null;
        }

        // If the path is already context-relative, just pass it through
        if (path == null) {
            return null;
        } else if (path.startsWith("/")) {
            return (context.getServletContext().getRequestDispatcher(path));
        }

        // Convert a request-relative path to a context-relative one
        String servletPath = (String) getAttribute(
                RequestDispatcher.INCLUDE_SERVLET_PATH);
        if (servletPath == null) {
            servletPath = getServletPath();
        }

        // Add the path info, if there is any
        String pathInfo = getPathInfo();
        String requestPath = null;

        if (pathInfo == null) {
            requestPath = servletPath;
        } else {
            requestPath = servletPath + pathInfo;
        }

        int pos = requestPath.lastIndexOf('/');
        String relative = null;
        if (context.getDispatchersUseEncodedPaths()) {
            if (pos >= 0) {
                relative = URLEncoder.DEFAULT.encode(
                        requestPath.substring(0, pos + 1), "UTF-8") + path;
            } else {
                relative = URLEncoder.DEFAULT.encode(requestPath, "UTF-8") + path;
            }
        } else {
            if (pos >= 0) {
                relative = requestPath.substring(0, pos + 1) + path;
            } else {
                relative = requestPath + path;
            }
        }

        return context.getServletContext().getRequestDispatcher(relative);
    }

Wrapper
Wrapper是context的子容器,它封裝的處理資源的每一個具體的servlet。

主要說說servlet對象與servlet stack對象。這兩個對象在wrapper容器中只存在其中之一,也就是說只有其中一個不爲空。當以servlet對象存在時,說明此servlet是支持多線程併發訪問的,也就是說不存在線程同步的過程,此wrapper容器中只包含一個servlet對象(這是咱們經常使用的模式);當以servlet stack對象存在時,說明servlet是不支持多線程併發訪問的,每一個servlet對象任一時刻只有一個線程能夠調用,這樣servlet stack實現的就是個簡易的線程池,此wrapper容器中只包含一組servlet對象,它的基本原型是worker thread模式實現的。 


那麼,怎麼來決定是以servlet對象方式存儲仍是servlet stack方式存儲呢?其實,只要在開發servlet類時,實現一個SingleThreadModel接口便可。

public class LoginServlet extends HttpServlet implements javax.servlet.SingleThreadModel

可是值得注意的是,這種同步機制只是從servlet規範的角度來講提供的一種功能,在實際應用中並不能徹底解決線程安全問題,例如若是servlet中有static數據訪問等,所以若是對線程安全又比較嚴格要求的,最好仍是用一些其餘的自定義的解決方案。

Wrapper的基本功能已經說了。那麼再說一個wrapper比較重要的概念。嚴格的說,並非每個訪問資源對應一個wrapper對象。而是每一種訪問資源對應一個wrapper對象。其大體可分爲三種:

  • 處理靜態資源的一個wrapper:例如html,jpg等靜態資源的wrapper,它包含了一個tomcat的實現處理靜態資源的缺省servlet:

         org.apache.catalina.servlets.DefaultServlet  

 

  • 處理jsp的一個wrapper:例如訪問的全部jsp文件,它包含了一個tomcat的實現處理jsp的缺省servlet:

          org.apache.jasper.servlet.JspServlet  


它主要實現了對jsp的編譯等操做

  • 處理servlet的若干wrapper:它包含了自定義的servlet對象,就是在web.xml中配置的servlet。


須要注意的是,前兩種wrapper分別是一個,主要是其對應的是DefaultServlet及JspServlet。這兩個servlet是在tomcat的全局conf目錄下的web.xml中配置的,當app啓動時,加載到內存中。

tomcat conf web.xml
<servlet>  
  <servlet-name>default</servlet-name>  
  <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>  
  <init-param>  
    <param-name>debug</param-name>  
    <param-value>0</param-value>  
  </init-param>  
  <init-param>  
    <param-name>listings</param-name>  
    <param-value>false</param-value>  
  </init-param>  
  <load-on-startup>1</load-on-startup>  
</servlet>  
   
<servlet>  
  <servlet-name>jsp</servlet-name>  
  <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>  
  <init-param>  
    <param-name>fork</param-name>  
    <param-value>false</param-value>  
  </init-param>  
  <init-param>  
    <param-name>xpoweredBy</param-name>  
    <param-value>false</param-value>  
  </init-param>  
  <load-on-startup>3</load-on-startup>  
</servlet>
相關文章
相關標籤/搜索