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需要你更改一下变量名就成了
- Tomcat从零开始(八)Lifecycle
- Tomcat 源码阅读(八)Lifecycle
- (八)maven核心概念-生命周期(Lifecycle)
- Tomcat Lifecycle
- Tomcat中Lifecycle详解(源码阅读)
- Tomcat学习6.1(生命周期Lifecycle)
- 从零开始学Android(八)
- 从零开始学Makefile(八)
- Tomcat从零开始(一)
- Tomcat从零开始(五)
- Tomcat 8(九)解读Tomcat组件的生命周期(Lifecycle)
- Tomcat 8(九)解读Tomcat组件的生命周期(Lifecycle)
- tomcat中的Lifecycle架构
- Tomcat源码Lifecycle分析
- tomcat 容器生命周期lifecycle
- tomcat Lifecycle设计模式
- tomcat 容器生命周期lifecycle
- Tomcat源码分析-Lifecycle
- Ubuntu 下安装并配置mysql+php+apache
- HDU 2191 多重背包
- php 实现其中的单选按钮控制文本框的显示与隐藏
- hadoop 进阶实例
- Code Jam练习
- Tomcat从零开始(八)Lifecycle
- java中的clone
- Grinder测试脚本
- NSThread
- 基于linux的集群系统(一)
- Ubuntu下装QQ2013,让linux小白们不怕脱离windows(更新)
- MFC框架各部分指针获取方式
- memcached全面剖析
- SQL with as 的用法 以及递归函数的写法