how tomcat works 總結 二


第五章 servlet容器

第 5 章討論 container 模塊。container 指的是 org.apache.catalina.Container 接口,有4 種類型的 container:engine, host, context 和 wrapper。這章提供了兩個工做於 context 和wrapper 的程序。
容器共分四類,類圖例如如下:

一個wrapper就是一個servlet;
一個context包括若干個wrapper;
本章分了兩個部分,第一部分是wrapper,第二部分是context。


第一部分 wrapper

這一章說白了就是具體分解了第四章SimpleContainer中的invoke方法!
public class SimpleWrapper implements Wrapper, Pipeline {

  // the servlet instance
  private Servlet instance = null;
  private String servletClass;
  private Loader loader;
  private String name;
  private SimplePipeline pipeline = new SimplePipeline(this);
  protected Container parent = null;
    public SimpleWrapper() {
    pipeline.setBasic(new SimpleWrapperValve());
  }

  public synchronized void addValve(Valve valve) {
    pipeline.addValve(valve);
  }
  ...
}
既然說到了容器,就得說說管道(每一級容器中,都有一個管道);把咱們的命令比做流水,在(流水)命令接觸終於的servlet以前,會有一個長長的管道(SimplePipeline),管道里有一個一個的閥(Valve),每一個閥都會作一個任務!就這麼簡單,在管道里面有一個基礎閥(SimpleWrapperValve),而這個基礎閥就用來生成servlet,調用其service方法。


wrapper程序的類圖例如如下:

流程例如如下
先是調用wrapper的invoke;
java

SimpleWrapper.java
  public void invoke(Request request, Response response)
    throws IOException, ServletException {
    pipeline.invoke(request, response);
  }
再調用管道的invoke;
SimplePipeline.java
    public void invoke(Request request, Response response)
    throws IOException, ServletException {
    // Invoke the first Valve in this pipeline for this request
    (new SimplePipelineValveContext()).invokeNext(request, response);
  }
  SimplePipelineValveContext爲SimplePipeline的內部類,做用就是循環所有的閥,最後調用基礎閥(就是如下代碼中的basic)
  SimplePipelineValveContext.java
   public void invokeNext(Request request, Response response)
      throws IOException, ServletException {
      int subscript = stage;
      stage = stage + 1;
      // Invoke the requested Valve for the current request thread
      if (subscript < valves.length) {
        valves[subscript].invoke(request, response, this);
      }
      else if ((subscript == valves.length) && (basic != null)) {
        basic.invoke(request, response, this);
      }
      else {
        throw new ServletException("No valve");
      }
    }


 這部分的基礎閥就是SimpleWrapperValve(在構造simplewrapper時就指定了),基礎閥會調用反射生成servlet類......

 第二部分 context

 類圖例如如下:



 絕大部分的web程序不可能僅僅有一個servlet,多個servlet就會構成一個context。
 換句話說,一個context裏面有多個wrapper。
 那麼現在就有問題了,多個wrapper總得有個記錄,請求1應該讓哪一個wrapper來處理,請求2又該讓哪一個wrapper處理等等。


 所以就有了mapper接口,咱們這裏用的是事實上現類,simplecontextmapper。其map方法就能返回對應的wrapper。
web

 public Container map(Request request, boolean update) {

    String requestURI = ((HttpRequest) request).getDecodedRequestURI();
    String relativeURI = requestURI.substring(contextPath.length());

    Wrapper wrapper = null;

    String name = context.findServletMapping(relativeURI);
    if (name != null)
      wrapper = (Wrapper) context.findChild(name);
    return (wrapper);
  }
  找到wrapper就和上一部分的過程同樣了。

第六章 生命週期

第 6 章解釋了 Lifecycle 接口。這個接口定義了一個 Catalina 組件的生命週期。並提供了一個優雅的方式。用來把在該組件發生的事件通知其它組件。另外。Lifecycle 接口提供了一個優雅的機制,用於在 Catalina 經過單一的 start/stop 來啓動和中止組件。


本章類圖:

tomcat是組件化的軟件。所有的組件都實現了Lifecycle接口,裏面有start與stop方法;咱們現在想要的效果就是,我僅僅用啓動一個組件系統就能幫我把所有的都啓動,關閉也是同樣。apache

看上去很是複雜,事實上很是easy
tomcat

public synchronized void start() throws LifecycleException {
    if (started)
      throw new LifecycleException("SimpleContext has already started");

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    started = true;
    try {
      // Start our subordinate components, if any
      if ((loader != null) && (loader instanceof Lifecycle))
        ((Lifecycle) loader).start();

      // Start our child containers, if any
      Container children[] = findChildren();
      for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Lifecycle)
          ((Lifecycle) children[i]).start();
      }

      // Start the Valves in our pipeline (including the basic),
      // if any
      if (pipeline instanceof Lifecycle)
        ((Lifecycle) pipeline).start();
      // Notify our interested LifecycleListeners
      lifecycle.fireLifecycleEvent(START_EVENT, null);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
SimpleContext裏面的各個組件依次啓動就ok;
事實上這一章假設僅僅是說生命週期的話到這就結束了,可是假設說到觀察者模式,那話就多了。
所謂觀察者模式,說的簡單點就是,我有了一個動做,就要通知一些關心個人人。就這麼簡單。


Bootstrap.java
    LifecycleListener listener = new SimpleContextLifecycleListener();
    ((Lifecycle) context).addLifecycleListener(listener);

simplecontext.java
protected LifecycleSupport lifecycle = new LifecycleSupport(this);

public void addLifecycleListener(LifecycleListener listener) {
    lifecycle.addLifecycleListener(listener);
  }
  執行時,如下的代碼就是告訴所有關心SimpleContext的監聽者:SimpleContext類作了BEFORE_START_EVENT這個動做!
 lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
LifecycleSupport.java
  public void fireLifecycleEvent(String type, Object data) {

        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = null;
        synchronized (listeners) {
            interested = (LifecycleListener[]) listeners.clone();
        }
        for (int i = 0; i < interested.length; i++)      //循環通知所有關注者
            interested[i].lifecycleEvent(event);
    }

// 一個詳細的關注者
public class SimpleContextLifecycleListener implements LifecycleListener {

  @SuppressWarnings("unused")
public void lifecycleEvent(LifecycleEvent event) {
    Lifecycle lifecycle = event.getLifecycle();
    System.out.println("SimpleContextLifecycleListener's event " +event.getType().toString());
    if (Lifecycle.START_EVENT.equals(event.getType())) {
      System.out.println("Starting context.");
    }
    else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
      System.out.println("Stopping context.");
    }
  }
}
相關文章
相關標籤/搜索