• 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;

    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。

     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方法;我们如今想要的效果就是,我仅仅用启动一个组件系统就能帮我把全部的都启动,关闭也是一样。

    看上去非常复杂,事实上非常easy

    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.");
        }
      }
    }


  • 相关阅读:
    level trigger 与 edge trigger 的区别
    使用ifstream时碰到的一个小问题
    转一篇 sed one line
    select(poll)效率,与异步网络IO,AIO, libevent, epoll
    类的成员函数指针的使用
    awk 的OFS使用 小 tips
    一句话打通所有机器,小脚本
    usleep sleep函数会重置clock 的返回值
    qstore 的 chunk重构小记
    判断质数的方法
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/6713239.html
Copyright © 2020-2023  润新知