tomcat源碼分析學習筆記(五)

——每天的寥寥幾筆,堅持下去,將會是一份份沉甸甸的積累


上一篇文章講到了servlet容器的wrapper,這篇繼續上一篇來講講第二種容器context。

之前講過context的層次在wrapper之上,可以包含多個wrapper,一個wrapper完成對一個serlvet的處理,多個wrapper的時候,我們就要面臨選擇,確定到底由哪個wrapper來處理,也就是涉及到了映射查找對應的wrapper。


1.先來看看一個simpleContext

<span style="font-size:12px;">public class SimpleContext implements Context, Pipeline {

  public SimpleContext() {
    pipeline.setBasic(new SimpleContextValve());//依舊是設置基礎閥,同上一篇文章的介紹
  }

  protected HashMap children = new HashMap();//添加子wrapper
  protected Loader loader = null;
  protected SimplePipeline pipeline = new SimplePipeline(this);//同上一篇文章
  protected HashMap servletMappings = new HashMap();//URL下的servlet與相應wrapper的鍵值對映射******
  //映射器。爲了支持不同的協議。注意是協議。比如http,https兩個協議,如果請求相同的servlet,處理的wrapper是不一樣的
  protected Mapper amapper = null;//默認映射器
  protected HashMap mappers = new HashMap();//所有可用的映射器,第一個添加到容器中的映射器爲默認映射器
  private Container parent = null;</span>


2.那又是如何映射查找對應的wrapper。流程如下:

(1)起點定在基礎閥(因爲基礎閥負責創建出serlvet實例,調用service方法)。

<span style="font-size:12px;"> wrapper = (Wrapper) context.map(request, true);</span>


(2)調用Context的map方法,判斷傳入的request對象的協議是否符合要求,不符合返回null,符合則調用SimpleContextMapper的map方法

<span style="font-size:12px;">  public Container map(Request request, boolean update) {
    Mapper mapper = findMapper(request.getRequest().getProtocol());
    if (mapper == null)
      return (null);
    return (mapper.map(request, update));
  }</span>


(3)調用SimpleContextMapper的map方法。通過協議的測試後,就直接開始解析requestURL中請求的serlvet名,根據serlvet名映射找到具體wrapper名

<span style="font-size:12px;">public Container map(Request request, boolean update) {
    // Identify the context-relative URI to be mapped
    String contextPath =
      ((HttpServletRequest) request.getRequest()).getContextPath();
    String requestURI = ((HttpRequest) request).getDecodedRequestURI();
    String relativeURI = requestURI.substring(contextPath.length());
    // Apply the standard request URI mapping rules from the specification
    Wrapper wrapper = null;
    String servletPath = relativeURI;
    String pathInfo = null;
    String name = context.findServletMapping(relativeURI);//根據serlvet名映射查找serlvetMappings那張hashmap,找到具體wrapper名
    if (name != null)
      wrapper = (Wrapper) context.findChild(name);//根據上面找到的wrapper名,確定Context的child Wrappper.
    return (wrapper);
  }</span>


(4)拿到了wrapper,後面的操作同前一篇的操作,可參考tomcat源碼分析學習筆記(三)


(5)最後貼上測試的啓動類,那就更明晰了。

public final class Bootstrap2 {
  public static void main(String[] args) {
    HttpConnector connector = new HttpConnector();
    Wrapper wrapper1 = new SimpleWrapper();
    wrapper1.setName("Primitive");//給wrapper取名
    wrapper1.setServletClass("PrimitiveServlet");
    
    Wrapper wrapper2 = new SimpleWrapper();
    wrapper2.setName("Modern");
    wrapper2.setServletClass("ModernServlet");

    Context context = new SimpleContext();
    context.addChild(wrapper1);
    context.addChild(wrapper2);

    Valve valve1 = new HeaderLoggerValve();
    Valve valve2 = new ClientIPLoggerValve();

    ((Pipeline) context).addValve(valve1);
    ((Pipeline) context).addValve(valve2);

    Mapper mapper = new SimpleContextMapper();
    mapper.setProtocol("http");
    context.addMapper(mapper);
    Loader loader = new SimpleLoader();
    context.setLoader(loader);
    // context.addServletMapping(pattern, name);
    context.addServletMapping("/Primitive", "Primitive");//添加requestUrl的解析結果和wrapper的映射關係
    context.addServletMapping("/Modern", "Modern");
    connector.setContainer(context);
    try {
      connector.initialize();
      connector.start();

      // make the application wait until we press a key.
      System.in.read();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}


就寫到這吧,有什麼問題歡迎提出。學生黨天天熬夜,也是蠻拼的了。一起加油。



發佈了52 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章