您的位置:首页 > 运维架构 > Tomcat

how tomcat works 总结 二

2014-11-03 17:51 337 查看

第五章 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方法;我们现在想要的效果就是,我只用启动一个组件系统就能帮我把所有的都启动,关闭也是一样。看上去很复杂,其实很简单

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.");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: