淺讀tomcat架構設計之Pipeline-Valve管道(4)

飄渺紅塵✨發表於2021-07-09

  tomcat Container容器處理請求是使用Pipeline-Valve管道來處理的,後續寫的tomcat記憶體馬,和他緊密結合

  Pipeline-Valve是責任鏈模式,責任鏈模式是指在一個請求處理的過程有多個處理者依次對請求進行處理,每個處理者負責做自己相應的處理,處理完成後將處理後的請求返回,再讓下一個處理者繼續處理. 簡單點來說就是Pipeline就是請求,發起各種請求, Valve用於處理過來的所有請求,你的請求都會走Valve,進行處理檢查.

  (1)每個Pipeline都有特定的Valve,而且是在管道的最後一個執行,Valve的介面實現類是ValveBase

  (2)在上層容器的管道的ValveBase會呼叫下層容器的管道

  ValveBase的子類,有很多,分別有這些:

   我著重講下這四個子類

  其中要講的是這四個類,他們和Context,Engine,Host和Wrapper的請求處理息息相關.

  Pipeline-Valve的實現方法:

  Pipeline的介面實現類是org.apache.catalina.core.StandardPipeline:

    StandardPipeline繼承自LifecycleBase,所以StandardPipeline是生命週期類

  檢視startInternal方法:

    

  protected synchronized void startInternal() throws LifecycleException {
        Valve current = this.first;
        if (current == null) {
            current = this.basic;
        }

        for(; current != null; current = current.getNext()) {
            if (current instanceof Lifecycle) {
                ((Lifecycle)current).start();
            }
        }

        this.setState(LifecycleState.STARTING);
    }

  

  學過資料結構的話,會感到很熟悉,我部落格文章之前寫過類似的程式碼,他是個鏈式結構,遍歷所有的Valve並呼叫start方法,最後設定狀態.

   stopInternal和destroyInternal方法如下:

  protected synchronized void stopInternal() throws LifecycleException {
        this.setState(LifecycleState.STOPPING);
        Valve current = this.first;
        if (current == null) {
            current = this.basic;
        }

        for(; current != null; current = current.getNext()) {
            if (current instanceof Lifecycle) {
                ((Lifecycle)current).stop();
            }
        }

    }

    protected void destroyInternal() {
        Valve[] valves = this.getValves();
        Valve[] arr$ = valves;
        int len$ = valves.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            Valve valve = arr$[i$];
            this.removeValve(valve);
        }

    }

  程式碼和startInternal相似,都是使用current臨時變數遍歷Valve的所有Valve,destoryInternal是刪除所有的valve

  

  Pipeline管道處理請求的實現方法:

  Engine,先從ValveBase的子類StandEngineValve類開始org.apache.catalina.core.StandardEngineValve

    Pipeline管道呼叫所包含Valve的invoke來處理請求,invoke方法來處理請求

    invoke方法:

    

  public final void invoke(Request request, Response response) throws IOException, ServletException {
        Host host = request.getHost();
        if (host == null) {
            response.sendError(400, sm.getString("standardEngine.noHost", new Object[]{request.getServerName()}));
        } else {
            if (request.isAsyncSupported()) {
                request.setAsyncSupported(host.getPipeline().isAsyncSupported());
            }

            host.getPipeline().getFirst().invoke(request, response);
        }
    }

 

 

 

  首先通過reuquest獲取Host站點,然後呼叫管道的第一個Valve的invoke方法進行處理

  

  Host,org.apache.catalina.core.StandardHostValve#invoke方法:    

 

  程式碼太長,擷取部分,Host的ValveBase呼叫的是Context的Pipeline

  Context,org.apache.catalina.core.StandardContextValve#invoke方法:

    

 

   程式碼太長,擷取部分,Context的ValveBase呼叫的是Wrapper的Pipeline

  Wrapper,org.apache.catalina.core.StandardWrapperValve#invoke方法:

    

 

 

      

 

 

    程式碼太長,擷取部分,Wrapper是封裝Servlet的,ValveBase內部呼叫的是filterChain來處理請求的

  Filter和Servlet的實際處理請求的方法在Wrapper的管道Pipeline->Valve-ValveBase-StandardWrapperValve#invoke方法中呼叫,Wrapper生命週期是在org.apache.catalina.core.StandardWrapper中呼叫,因為StandardWrapper繼承自ContainerBase,ContainerBase又繼承自LifecycleMBeanBase  

相關文章