Tomcat从零开始(八)Lifecycle

来源:互联网 发布:unity3d灯光教程 编辑:程序博客网 时间:2024/05/17 04:14

第八课:

Catalina是由很多部分组成的,所以当服务器启动的时候,tomcat需要去调用servlet的init方法和初始化容器等一系列操作,而停止的时候,也需要调用servlet的destory方法。而这些都是通过org.apache.catalina.Lifecycle接口来实现的。

 

一般实现了Lifecycle接口的组件有以下六种事件,BEFORE/  / AFTER_ STRAT/ STOP  _ EVENT。那么我们就先来说一说Lifecycle 接口

 

Catalina 一般都是一个组件可以包含N个组件,就像容器那样。所以父组件负责启动和停止子组件,详情参见pipeline那一节。

这里没什么多说的,接下来看LifecycleEvent,看名字就知道他表示一个事件,之后就是LifecycleListener.这都是比较标准的 event-listener写法,这里就不多说了。

我们看看LifecycleSupport这个类,这个类的存在就简化了cycle的操作难度,首先,你这个类得实现lifecycle这个接口,之后你用this作为LifecycleSupport的构造器,创建出一个新的lifecycleSupport就可以了。

我们先看看Lifecycle、LifecycleEvent、LifecycleListener。如下图:

这个没什么说的,来看看LifecycleSupport这个类的源码,

package org.apache.catalina.util;import org.apache.catalina.Lifecycle;import org.apache.catalina.LifecycleEvent;import org.apache.catalina.LifecycleListener;public final class LifecycleSupport {    public LifecycleSupport(Lifecycle lifecycle) {        super();        this.lifecycle = lifecycle;    }    private Lifecycle lifecycle = null;    private LifecycleListener listeners[] = new LifecycleListener[0];    public void addLifecycleListener(LifecycleListener listener) {      synchronized (listeners) {          LifecycleListener results[] =            new LifecycleListener[listeners.length + 1];          for (int i = 0; i < listeners.length; i++)              results[i] = listeners[i];          results[listeners.length] = listener;          listeners = results;      }    }    public LifecycleListener[] findLifecycleListeners() {        return listeners;    }    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 void removeLifecycleListener(LifecycleListener listener) {        synchronized (listeners) {            int n = -1;            for (int i = 0; i < listeners.length; i++) {                if (listeners[i] == listener) {                    n = i;                    break;                }            }            if (n < 0)                return;            LifecycleListener results[] =              new LifecycleListener[listeners.length - 1];            int j = 0;            for (int i = 0; i < listeners.length; i++) {                if (i != n)                    results[j++] = listeners[i];            }            listeners = results;        }    }}

 我们可以看到,这个LifecycleListener 数组,对她进行增删操作的时候,都用synchronized关键字锁住了listeners,这是因为他们是用array实现的,所以 如果在多用户访问的时候,不对index进行锁定,那么很有可能数组下标越界,或者在删除的时候增加会造成数组元素被覆盖 等情况。所以采用synchronized。但是fire也就是触发为什么要用synchronized呢,为什么要另外建立一个LifecycleListener数组? 因为下面有一个遍历的操作,同样需要 处理多线程访问的问题。所以tomcat这样处理。


下面,我们来看看实现了Lifecycle的容器  的自制服务器- -。

首先就是 bootstrap.

public final class Bootstrap {  public static void main(String[] args) {    Connector connector = new HttpConnector();    //这里就不多说wrapper和context了,这些在容器那都说过了    Wrapper wrapper1 = new SimpleWrapper();    wrapper1.setName("Primitive");    wrapper1.setServletClass("PrimitiveServlet");    Wrapper wrapper2 = new SimpleWrapper();    wrapper2.setName("Modern");    wrapper2.setServletClass("ModernServlet");    Context context = new SimpleContext();    context.addChild(wrapper1);    context.addChild(wrapper2);    Mapper mapper = new SimpleContextMapper();    //设置协议    mapper.setProtocol("http");    LifecycleListener listener = new SimpleContextLifecycleListener();    //添加listener    ((Lifecycle) context).addLifecycleListener(listener);    context.addMapper(mapper);    Loader loader = new SimpleLoader();    context.setLoader(loader);    //设置映射关系    context.addServletMapping("/Primitive", "Primitive");    context.addServletMapping("/Modern", "Modern");    connector.setContainer(context);    try {      connector.initialize();      ((Lifecycle) connector).start();      ((Lifecycle) context).start();      System.in.read();      ((Lifecycle) context).stop();    }    catch (Exception e) {      e.printStackTrace();    }  }}

这个没什么说的,东西都在注释上。接下来SimpleContext,它这个首先得重写一个addServletMapping方法,让它直接存储到SimpleContext的hashmap中就可以,注意要用synchronized。同样findSErXXX这个也需要重写。之后就是它的Lifecycle接口的方法。

public synchronized void start() throws LifecycleException {    if (started)      throw new LifecycleException("SimpleContext has already started");    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);    started = true;    try {      if ((loader != null) && (loader instanceof Lifecycle))        ((Lifecycle) loader).start();      Container children[] = findChildren();      for (int i = 0; i < children.length; i++) {        if (children[i] instanceof Lifecycle)          ((Lifecycle) children[i]).start();      }      if (pipeline instanceof Lifecycle)        ((Lifecycle) pipeline).start();      lifecycle.fireLifecycleEvent(START_EVENT, null);    }    catch (Exception e) {      e.printStackTrace();    }    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);  }  public void stop() throws LifecycleException {    if (!started)      throw new LifecycleException("SimpleContext has not been started");    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);    lifecycle.fireLifecycleEvent(STOP_EVENT, null);    started = false;    try {      if (pipeline instanceof Lifecycle) {        ((Lifecycle) pipeline).stop();      }      Container children[] = findChildren();      for (int i = 0; i < children.length; i++) {        if (children[i] instanceof Lifecycle)          ((Lifecycle) children[i]).stop();      }      if ((loader != null) && (loader instanceof Lifecycle)) {        ((Lifecycle) loader).stop();      }    }    catch (Exception e) {      e.printStackTrace();    }    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);  }
之后看看自己实现的Listener这个类,这个类没什么多说的,就是普通的方法调用

public class SimpleContextLifecycleListener implements LifecycleListener {  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.");    }  }}

接下来就是Mapper类了,这个主要的就是从request取出不同的目录

public class SimpleContextMapper implements Mapper {  private SimpleContext context = null;  public Container getContainer() {    return (context);  }  public void setContainer(Container container) {    if (!(container instanceof SimpleContext))      throw new IllegalArgumentException        ("Illegal type of container");    context = (SimpleContext) container;  }  public String getProtocol() {    return null;  }  public void setProtocol(String protocol) {  }  public Container map(Request request, boolean update) {    if (update && (request.getWrapper() != null))      return (request.getWrapper());    String contextPath =      ((HttpServletRequest) request.getRequest()).getContextPath();    String requestURI = ((HttpRequest) request).getDecodedRequestURI();    String relativeURI = requestURI.substring(contextPath.length());    Wrapper wrapper = null;    String servletPath = relativeURI;    String pathInfo = null;    String name = context.findServletMapping(relativeURI);    if (name != null)      wrapper = (Wrapper) context.findChild(name);    if (update) {      request.setWrapper(wrapper);      ((HttpRequest) request).setServletPath(servletPath);      ((HttpRequest) request).setPathInfo(pathInfo);    }    return (wrapper);  }}
至于Valve这个类,就不多说了,无非就是invoke和一个内部类 中的invokeNext方法,第六课应该说过了。Loader, pipeline就没什么说的了。都是上几节课的内容。来看看Wrapper的Lifecycle的内容。

public synchronized void start() throws LifecycleException {    System.out.println("Starting Wrapper " + name);    if (started)      throw new LifecycleException("Wrapper already started");    // 触发所有before_start_event的事件    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);    started = true;    // 启动组件    if ((loader != null) && (loader instanceof Lifecycle))      ((Lifecycle) loader).start();    // 开启pipeline去逐个valve    if (pipeline instanceof Lifecycle)      ((Lifecycle) pipeline).start();    lifecycle.fireLifecycleEvent(START_EVENT, null);    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);  }  public void stop() throws LifecycleException {    System.out.println("Stopping wrapper " + name);    try {      instance.destroy();    }    catch (Throwable t) {    }    instance = null;    if (!started)      throw new LifecycleException("Wrapper " + name + " not started");    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);    lifecycle.fireLifecycleEvent(STOP_EVENT, null);    started = false;    if (pipeline instanceof Lifecycle) {      ((Lifecycle) pipeline).stop();    }    if ((loader != null) && (loader instanceof Lifecycle)) {      ((Lifecycle) loader).stop();    }    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);  }


刚有人私信问我他把tomcat1.4的源码直接复制进来,有很多错误,其实这个错误就是enum类的问题,那时候enum还不是 关键字。1.5版本以后的jdk需要你更改一下变量名就成了

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 刚买的小狗怕人怎么办 一年级孩子字写不好怎么办 小狗三天没吃了怎么办 捡到一只流浪猫怎么办 仓鼠四肢红肿圈状怎么办 泰迪的鼻子干燥怎么办 小狗眼睛有白色浓稠物怎么办 流浪狗生了小狗怎么办 学生字写得很差怎么办 猫身上粘老鼠胶怎么办 抄东西抄的手疼怎么办 皮质物品被油性笔划了怎么办 在小区猫丢了怎么办 母猫把小猫丢了怎么办 小狗不吃东西没精神怎么办 小狗的鼻子烂了怎么办 狗老是在家拉尿怎么办 狗狗鼻子有点干怎么办 狗的鼻头不黑了怎么办 金毛鼻头不黑怎么办 金毛毛掉了不长怎么办 狗狗鼻子烂了怎么办 小比熊鼻子不黑怎么办 狗狗鼻子起皮怎么办 金鱼身子弯了是怎么办 属狗的纹龙怎么办 卫生间的墙空的怎么办 花生苗长得好怎么办 菊花上面的白虫怎么办 小狗不吃东西还吐怎么办 小狗呕吐不吃东西没精神怎么办 小狗生病了不吃东西怎么办 小兔子腿摔了怎么办 刺猬葡萄我们骄傲我们该怎么办 小狗被邻居家大狗咬死了怎么办 狗狗死胎在腹中怎么办 小狗不吃饭没精神怎么办 虎皮鹦鹉生蛋了怎么办 钢笔替换芯干了怎么办 水芯钢笔不出水怎么办 被红斑蛇咬了怎么办