Tomcat源碼分析 (四)—– Pipeline和Valve

  • 2019 年 10 月 3 日
  • 筆記

在 Tomcat源碼分析 (二)—– Tomcat整體架構及組件 中我們簡單分析了一下Pipeline和Valve,並給出了整體的結構圖。而這一節,我們將詳細分析Tomcat裡面的源碼。

 

Valve

Valve作為一個個基礎的閥門,扮演著業務實際執行者的角色。我們看看Valve這個介面有哪些方法。

public interface Valve {      // 獲取下一個閥門      public Valve getNext();      // 設置下一個閥門      public void setNext(Valve valve);      // 後台執行邏輯,主要在類載入上下文中使用到      public void backgroundProcess();      // 執行業務邏輯      public void invoke(Request request, Response response)          throws IOException, ServletException;      // 是否非同步執行      public boolean isAsyncSupported();  }

Contained

ValveBasePipeline及其他相關組件都實現了Contained介面,我們看看這個介面有哪些方法。很簡單,就是get/set容器操作。

public interface Contained {        /**       * Get the {@link Container} with which this instance is associated.       *       * @return The Container with which this instance is associated or       *         <code>null</code> if not associated with a Container       */      Container getContainer();          /**       * Set the <code>Container</code> with which this instance is associated.       *       * @param container The Container instance with which this instance is to       *  be associated, or <code>null</code> to disassociate this instance       *  from any Container       */      void setContainer(Container container);  }

ValveBase

從Valve的類層次結構,我們發現幾乎所有Valve都繼承了ValveBase這個抽象類,所以這兒我們需要分析一下它。

public abstract class ValveBase extends LifecycleMBeanBase implements Contained, Valve {      // 國際化管理器,可以支援多國語言      protected static final StringManager sm = StringManager.getManager(ValveBase.class);        //------------------------------------------------------ Instance Variables        // 無參構造方法,默認不支援非同步      public ValveBase() {          this(false);      }      // 有參構造方法,可傳入非同步支援標記      public ValveBase(boolean asyncSupported) {          this.asyncSupported = asyncSupported;      }          //------------------------------------------------------ Instance Variables        // 非同步標記      protected boolean asyncSupported;      // 所屬容器      protected Container container = null;      // 容器日誌組件對象      protected Log containerLog = null;      // 下一個閥門      protected Valve next = null;          //-------------------------------------------------------------- Properties        // 獲取所屬容器      @Override      public Container getContainer() {          return container;      }      // 設置所屬容器      @Override      public void setContainer(Container container) {          this.container = container;      }      // 是否非同步執行      @Override      public boolean isAsyncSupported() {          return asyncSupported;      }      // 設置是否非同步執行      public void setAsyncSupported(boolean asyncSupported) {          this.asyncSupported = asyncSupported;      }      // 獲取下一個待執行的閥門      @Override      public Valve getNext() {          return next;      }      // 設置下一個待執行的閥門      @Override      public void setNext(Valve valve) {          this.next = valve;      }          //---------------------------------------------------------- Public Methods        // 後台執行,子類實現      @Override      public void backgroundProcess() {          // NOOP by default      }      // 初始化邏輯      @Override      protected void initInternal() throws LifecycleException {          super.initInternal();          // 設置容器日誌組件對象到當前閥門的containerLog屬性          containerLog = getContainer().getLogger();      }      // 啟動邏輯      @Override      protected synchronized void startInternal() throws LifecycleException {          setState(LifecycleState.STARTING);      }      // 停止邏輯      @Override      protected synchronized void stopInternal() throws LifecycleException {          setState(LifecycleState.STOPPING);      }      // 重寫toString,格式為[${containerName}]      @Override      public String toString() {          StringBuilder sb = new StringBuilder(this.getClass().getName());          sb.append('[');          if (container == null) {              sb.append("Container is null");          } else {              sb.append(container.getName());          }          sb.append(']');          return sb.toString();      }          // -------------------- JMX and Registration  --------------------        // 設置獲取MBean對象的keyProperties,格式如:a=b,c=d,e=f...      @Override      public String getObjectNameKeyProperties() {          StringBuilder name = new StringBuilder("type=Valve");            Container container = getContainer();            name.append(container.getMBeanKeyProperties());            int seq = 0;            // Pipeline may not be present in unit testing          Pipeline p = container.getPipeline();          if (p != null) {              for (Valve valve : p.getValves()) {                  // Skip null valves                  if (valve == null) {                      continue;                  }                  // Only compare valves in pipeline until we find this valve                  if (valve == this) {                      break;                  }                  if (valve.getClass() == this.getClass()) {                      // Duplicate valve earlier in pipeline                      // increment sequence number                      seq ++;                  }              }          }            if (seq > 0) {              name.append(",seq=");              name.append(seq);          }            String className = this.getClass().getName();          int period = className.lastIndexOf('.');          if (period >= 0) {              className = className.substring(period + 1);          }          name.append(",name=");          name.append(className);            return name.toString();      }      // 獲取所屬域,從container獲取      @Override      public String getDomainInternal() {          Container c = getContainer();          if (c == null) {              return null;          } else {              return c.getDomain();          }      }  }

Pipeline

Pipeline作為一個管道,我們可以簡單認為是一個Valve的集合,內部會對這個集合進行遍歷,調用每個元素的業務邏輯方法invoke()

是不是這樣呢?我們還是分析一下源碼,先看看介面定義。

public interface Pipeline {      // ------------------------------------------------------------- Properties        // 獲取基本閥門      public Valve getBasic();      // 設置基本閥門      public void setBasic(Valve valve);        // --------------------------------------------------------- Public Methods        // 添加閥門      public void addValve(Valve valve);      // 獲取閥門數組      public Valve[] getValves();      // 刪除閥門      public void removeValve(Valve valve);      // 獲取首個閥門      public Valve getFirst();      // 管道內所有閥門是否非同步執行      public boolean isAsyncSupported();      // 獲取管道所屬的容器      public Container getContainer();      // 設置管道所屬的容器      public void setContainer(Container container);      // 查找非非同步執行的所有閥門,並放置到result參數中,所以result不允許為null      public void findNonAsyncValves(Set<String> result);  }

StandardPipeline

接著我們分析一下Pipeline唯一的實現StandardPipeline。程式碼很長,但是都很簡單。

public class StandardPipeline extends LifecycleBase          implements Pipeline, Contained {        private static final Log log = LogFactory.getLog(StandardPipeline.class);        // ----------------------------------------------------------- Constructors        // 構造一個沒有所屬容器的管道      public StandardPipeline() {          this(null);      }        // 構造一個有所屬容器的管道      public StandardPipeline(Container container) {          super();          setContainer(container);      }        // ----------------------------------------------------- Instance Variables        /**       * 基本閥門,最後執行的閥門       */      protected Valve basic = null;        /**       * 管道所屬的容器       */      protected Container container = null;        /**       * 管道裡面的首個執行的閥門       */      protected Valve first = null;        // --------------------------------------------------------- Public Methods        // 是否非同步執行,如果一個閥門都沒有,或者所有閥門都是非同步執行的,才返回true      @Override      public boolean isAsyncSupported() {          Valve valve = (first!=null)?first:basic;          boolean supported = true;          while (supported && valve!=null) {              supported = supported & valve.isAsyncSupported();              valve = valve.getNext();          }          return supported;      }        // 查找所有未非同步執行的閥門      @Override      public void findNonAsyncValves(Set<String> result) {          Valve valve = (first!=null) ? first : basic;          while (valve != null) {              if (!valve.isAsyncSupported()) {                  result.add(valve.getClass().getName());              }              valve = valve.getNext();          }      }        // ------------------------------------------------------ Contained Methods        // 獲取所屬容器      @Override      public Container getContainer() {          return (this.container);      }        // 設置所屬容器      @Override      public void setContainer(Container container) {          this.container = container;      }        // 初始化邏輯,默認沒有任何邏輯      @Override      protected void initInternal() {          // NOOP      }        // 開始邏輯,調用所有閥門的start方法      @Override      protected synchronized void startInternal() throws LifecycleException {          // Start the Valves in our pipeline (including the basic), if any          Valve current = first;          if (current == null) {              current = basic;          }          while (current != null) {              if (current instanceof Lifecycle)                  ((Lifecycle) current).start();              current = current.getNext();          }            setState(LifecycleState.STARTING);      }        // 停止邏輯,調用所有閥門的stop方法      @Override      protected synchronized void stopInternal() throws LifecycleException {          setState(LifecycleState.STOPPING);            // Stop the Valves in our pipeline (including the basic), if any          Valve current = first;          if (current == null) {              current = basic;          }          while (current != null) {              if (current instanceof Lifecycle)                  ((Lifecycle) current).stop();              current = current.getNext();          }      }        // 銷毀邏輯,移掉所有閥門,調用removeValve方法      @Override      protected void destroyInternal() {          Valve[] valves = getValves();          for (Valve valve : valves) {              removeValve(valve);          }      }        /**       * 重新toString方法       */      @Override      public String toString() {          StringBuilder sb = new StringBuilder("Pipeline[");          sb.append(container);          sb.append(']');          return sb.toString();      }        // ------------------------------------------------------- Pipeline Methods        // 獲取基礎閥門      @Override      public Valve getBasic() {          return (this.basic);      }        // 設置基礎閥門      @Override      public void setBasic(Valve valve) {          // Change components if necessary          Valve oldBasic = this.basic;          if (oldBasic == valve)              return;            // Stop the old component if necessary          // 老的基礎閥門會被調用stop方法且所屬容器置為null          if (oldBasic != null) {              if (getState().isAvailable() && (oldBasic instanceof Lifecycle)) {                  try {                      ((Lifecycle) oldBasic).stop();                  } catch (LifecycleException e) {                      log.error("StandardPipeline.setBasic: stop", e);                  }              }              if (oldBasic instanceof Contained) {                  try {                      ((Contained) oldBasic).setContainer(null);                  } catch (Throwable t) {                      ExceptionUtils.handleThrowable(t);                  }              }          }            // Start the new component if necessary          // 新的閥門會設置所屬容器,並調用start方法          if (valve == null)              return;          if (valve instanceof Contained) {              ((Contained) valve).setContainer(this.container);          }          if (getState().isAvailable() && valve instanceof Lifecycle) {              try {                  ((Lifecycle) valve).start();              } catch (LifecycleException e) {                  log.error("StandardPipeline.setBasic: start", e);                  return;              }          }            // Update the pipeline          // 替換pipeline中的基礎閥門,就是講基礎閥門的前一個閥門的next指向當前閥門          Valve current = first;          while (current != null) {              if (current.getNext() == oldBasic) {                  current.setNext(valve);                  break;              }              current = current.getNext();          }            this.basic = valve;      }        // 添加閥門      @Override      public void addValve(Valve valve) {          // Validate that we can add this Valve          // 設置所屬容器          if (valve instanceof Contained)              ((Contained) valve).setContainer(this.container);            // Start the new component if necessary          // 調用閥門的start方法          if (getState().isAvailable()) {              if (valve instanceof Lifecycle) {                  try {                      ((Lifecycle) valve).start();                  } catch (LifecycleException e) {                      log.error("StandardPipeline.addValve: start: ", e);                  }              }          }            // Add this Valve to the set associated with this Pipeline          // 設置閥門,將閥門添加到基礎閥門的前一個          if (first == null) {              first = valve;              valve.setNext(basic);          } else {              Valve current = first;              while (current != null) {                  if (current.getNext() == basic) {                      current.setNext(valve);                      valve.setNext(basic);                      break;                  }                  current = current.getNext();              }          }            container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve);      }        // 獲取閥門數組      @Override      public Valve[] getValves() {          ArrayList<Valve> valveList = new ArrayList<>();          Valve current = first;          if (current == null) {              current = basic;          }          while (current != null) {              valveList.add(current);              current = current.getNext();          }            return valveList.toArray(new Valve[0]);      }        // JMX方法,在此忽略      public ObjectName[] getValveObjectNames() {          ArrayList<ObjectName> valveList = new ArrayList<>();          Valve current = first;          if (current == null) {              current = basic;          }          while (current != null) {              if (current instanceof JmxEnabled) {                  valveList.add(((JmxEnabled) current).getObjectName());              }              current = current.getNext();          }            return valveList.toArray(new ObjectName[0]);      }        // 移除閥門      @Override      public void removeValve(Valve valve) {          Valve current;          if(first == valve) {              // 如果待移出的閥門是首個閥門,則首個閥門的下一個閥門變成首個閥門              first = first.getNext();              current = null;          } else {              current = first;          }          // 遍歷閥門集合,並進行移除          while (current != null) {              if (current.getNext() == valve) {                  current.setNext(valve.getNext());                  break;              }              current = current.getNext();          }            if (first == basic) first = null;            // 設置閥門所屬容器為null          if (valve instanceof Contained)              ((Contained) valve).setContainer(null);            // 調用待移除閥門的stop方法和destroy方法,並觸發移除閥門事件          if (valve instanceof Lifecycle) {              // Stop this valve if necessary              if (getState().isAvailable()) {                  try {                      ((Lifecycle) valve).stop();                  } catch (LifecycleException e) {                      log.error("StandardPipeline.removeValve: stop: ", e);                  }              }              try {                  ((Lifecycle) valve).destroy();              } catch (LifecycleException e) {                  log.error("StandardPipeline.removeValve: destroy: ", e);              }          }            container.fireContainerEvent(Container.REMOVE_VALVE_EVENT, valve);      }        // 獲取首個閥門,如果閥門列表為null,返回基礎閥門      @Override      public Valve getFirst() {          if (first != null) {              return first;          }          return basic;      }  }

總結

通過上面的程式碼分析,我們發現了幾個關鍵的設計模式:

  1. 模板方法模式,父類定義框架,子類實現
  2. 責任鏈模式,就是這兒的管道/閥門的實現方式,每個閥門維護一個next屬性指向下一個閥門