how tomcat works 讀書筆記 十一 StandWrapper 上

來源:互聯網
上載者:User

標籤:tomcat   多線程   servlet   讀書筆記   jsp   

方法調用序列

展示了方法調用的共同作業圖表:


 這個是前面第五章裡,我畫的圖:

 我們再回顧一下自從連接器裡
 connector.getContainer().invoke(request, response);
 這句代碼運行之後發生的事情;
 這是第五章的時序圖,放在這一章同樣適用。。。
 我們仔細分析一下:
 1首先連接器建立請求與響應對象;
 2調用這行代碼
   connector.getContainer().invoke(request, response)
   (我們一StandContext為頂層容器)
 3在容器裡會先調用StandardPipeline的invoke方法。如下:
   public void invoke(Request request, Response response)        throws IOException, ServletException {        // Invoke the first Valve in this pipeline for this request        (new StandardPipelineValveContext()).invokeNext(request, response);    }
 4StandardPipeline有個內部類StandardPipelineValveContext,它的invokeNext方法會迴圈管道(StandardContext的管道)裡的所有閥,直到基礎閥,並且調用其invoke方法。基礎閥在StandardContext初始化的時候就預設指定了StandardContextValve();
 5基礎閥的invoke方法調用StandardContext的map方法得到Wrapper
 6調用得到的wrapper(這裡是StandardWrapper)的invoke方法...
 7先重複上面的第三第四步,這時獲得的基礎閥是StandardWrapperValve,它的invoke方法就是調用StandardWrapper類的allocate方法,allocate調用loadServlet獲得servlet。
 8產生一個在ApplicationFilterChain:createFilterChain(request, servlet),然後在其internalDoFilter方法中調用servlet的service方法。
   
 SingleThreadModel介面 這個介面能保證,在容器內部,任何時候只有一個進程訪問某個serlvet的service方法。
 這個介面是一個空介面,或者叫標誌介面,內部什麼都沒有。就是一種標示而已。
 實現此介面的一個servlet通俗稱為SingleThreadModel(STM)的程式組件。
 很多程式員以為,只要實現了上述介面就能保證自己的servlet是安全執行緒的。
 其實不然,例如如果若干個servlet的service方法都訪問某個靜態類的變數或servelt類以外的類或變數呢?
 因而這個介面在Servlet 2.4中就已經廢棄了,就是因為它讓程式員產生了虛假的安全感。

 StandardWrapperStandardWrapper的主要作用就是載入它自己所代表的servlet類,並進行執行個體化,但是通過分析上面的調用時序圖,大家知道它是先調用自己的管道,然後是基礎閥,由基礎閥調用StandardWrapper的alloacte方法。
上面已經說了,有個STM,如果容器只是維護一個實現了STM介面的servelt那麼調用的時候就應該是這樣的
    Servlet instance = <get an instance of the servlet>;    if ((servlet implementing SingleThreadModel>) {        synchronized (instance) {            instance.service(request, response);        }    }    else {        instance.service(request, response);    }
不過為了保持效能,StandardWrapper一般維護了一個STM servlet 執行個體池。
一個封裝器還負責準備一個 javax.servlet.ServletConfig 的執行個體,這可以在
servlet 內部完成,接下來兩小節討論如何分配和載入 servlet。


 Alloacte方法 本方法其實可以分為兩部分:
 第一 產生非STMServlet
StandardWrapper 定義一個 java.servlet.Servlet 類型的執行個體
private Servlet instance = null;
方法 allocate 檢查該執行個體是否為 null,如果是調用 loadServlet 方法來載入servlet。然後增加 contAllocated 整型並返回該執行個體。

 第二 產生STMServlet
 方法 allocate 嘗試返回池中的一個執行個體,變數intancePool是一個java.util.Stack類型的 STM servlet執行個體池。
 在這裡我需要給大家解釋三個變數:
countAllocated: 目前存活的servelt數量
the count of allocations that are currently active (even if they are for the same instance, as will be true on a non-STM servlet).
nInstances : 已經載入的serlvet數量
Number of instances currently loaded for a STM servlet.
maxInstances: 這個看名字就知道了,StandardWrapper支援的最大數目的servlet。
上面三個變數肯定把大家搞暈了,但是我想說記著一個StandardWrapper就維護一個servlet,它只有一個class地址,那三個變數是在多線程的時候用的!
這部分的代碼比較麻煩,不管是理解還是說都很麻煩
總而言之,最開始的時候countAllocated與nInstances都是0,先loadServlet()出一個servelt,push到servlet執行個體池裡面,然後取出來..
這部分大家自己看代碼吧(我覺得自己偷的一把好懶呀)

loadServlet方法這個方法首先會回檢查instance,如果不為null,並且當前的StandardWrapper並不表示一個STMServlet類,那麼就直接返回。
另一方面,Catalina也是jsp容器,如果請求的servelt是一個jsp就執行下面的程式碼片段:
            String actualClass = servletClass;
            if ((actualClass == null) && (jspFile != null)) {
                Wrapper jspWrapper = (Wrapper)((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
                if (jspWrapper != null)
                    actualClass = jspWrapper.getServletClass();
            }
下面就是獲得classloader,預設情況下,我們看前面幾章的內容就知道,在Bootstrap裡我們就已經指定了WebappLoader,通過它,我們可以獲得WebappClassLoader這個對象。
不過在tomcat中,如果要載入的servlet位於org.apache.catalina.下,那麼classLoader就是
        classLoader = this.getClass().getClassLoader(); //this 就是StandardWrapper
再下來就是loadClass,接著用Class的newInstance獲得servlet;
下來就是檢查該servlet是否允許載入(這步我看的不是很懂),看它是否實現了ContainerServlet介面。
ContainerServlet介面中有set/getWrapper方法,就是可以讓servlet訪問Catalina的內部功能。
下面就是調用 servlet.init(facade);這個facade是javax.servlet.ServletConfig的一個外觀變數。
如果該StandardWrapper對象表示的是一個STM Servlet,將該執行個體添加到執行個體池中,因此,如果執行個體池如果為null,首先需要建立它。
   // Register our newly initialized instance
   singleThreadModel = servlet instanceof SingleThreadModel;
   if (singleThreadModel) {
    if (instancePool == null)
        instancePool = new Stack();
    }
    fireContainerEvent("load", this);
    }
 最後返回servlet。


 ServletConfig對象 上面servlet的init方法的參數實際上就是javax.servlet.ServletConfig介面的執行個體。
 問題出現了,這個介面的執行個體從哪來來呢?大家看看StandardWrapper的聲明部分,就知道它本身就實現了ServletConfig介面。
 但是在調用init方法是,StandardWrapper並不會直接把自己傳過去而是使用了一個facade,為什麼我主要是直接把StandardWrapper傳過去,那麼StandardWrapper裡面的所有public方法不都暴露了麼?
 ServletConfig 介面有以下四個方法getServletContext,getServletName,getInitParameter,和getInitParameterNames。

1 getServletContext
     public ServletContext getServletContext() {
        if (parent == null)
            return (null);
        else if (!(parent instanceof Context))
            return (null);
        else
            return (((Context) parent).getServletContext());
    }
現在你知道不能單獨部署一個封裝器來表示一個 Servlet,封裝器必須從屬於一個上下文容器,這樣才能使用 ServletConfig 對象使用getServletContext 方法獲得一個 ServletContext 執行個體。

2 getServletName
  獲得servlet的名字,沒有什麼好說的

3 getInitParameter
  獲得指定的初始參數的值。StandardWrapper中的初始參數放在一個HashMap中:
  private HashMap<String, String> parameters = new HashMap<String, String>();
  具體的實現大家看代碼,這塊很簡單。

4 getInitParameterNames
  返回的是初始化參數的名字的集合,是一個枚舉類。

StandardWrapperFacade類類圖如下:
ServletConfig共有四個方法,facade類getServletName,getInitParameter,getInitParameterNames都是直接調用StandardWrapper,這些都比較簡單,沒有什麼要說的。
不過getServletContext就有點複雜了:
    public ServletContext getServletContext() {
        ServletContext theContext = config.getServletContext();
        if ((theContext != null) &&
            (theContext instanceof ApplicationContext))
            theContext = ((ApplicationContext) theContext).getFacade();
        return (theContext);
    }
看到了吧,先調用StandardWrapper獲得Context,但是這裡最後給外面返回的還是Facade。(真tm複雜)。

下面的章節我們會講
StandardWrapperValve,FilterDef,ApplicationFilterConfig,ApplicationFilterChain

how tomcat works 讀書筆記 十一 StandWrapper 上

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.