Tomcat工作原理(五)-tomcat容器
一个tomcat容器需要实现org.apache.catalina.Container,你可以在tomcat的连接器中使用setContainer方法传递一个容器给连接器。
一个tomcat容器需要实现org.apache.catalina.Container,你可以在tomcat的连接器中使用setContainer方法传递一个容器给连接器。
Container接口
第一件需要注意的是在概念上tomcat有四种容器:
- Engine 代表整个Catalina的servlet引擎。
- Host 代表拥有若干个上下文的虚拟主机
- Context 代表一个web应用,一个Context拥有若干个wrapper
- Wrapper 代表一个单独的servlet
上述的每一个容器都在org.apache.catalina包中有对应的接口。这些接口都继承自Container,而StandardEngine, StandardHost, StandardContext, and StandardWrapper分别是他们的标准实现类
下图是他们的UML图:
一个“上层”容器可以拥有0个或者多个“下层容器”作为child,如一个Context可以拥有多个Wrapper ,但是Wrapper 作为作为最底层容器,不能拥有child。Container接口对于child进行了以下支持:
public void addChild(Container child);
public void removeChild(Container child);
public Container findChild(String name);
public Container[] findChildren();
一个容器也可以拥有其他的组件,比如Loader,Logger,Manager, Realm, and Resources这些将在以后的章节讨论。
更有趣的是 Container 接口被设计成 Tomcat 管理员可以通过server.xml 文件配置来决定其工作方式的模式它通过一个 pipeline(流水线)和一系列的阀门来实现,这些内容将会在下一节 Pipelining Task 中讨论。
Pipelining Tasks(流水线任务)
在这里主要要讨论的是其中的四个接口Pipeline(任务流), Valve(阀门), ValveContext, and Contained。
一个任务流包含了该容器要执行的所有任务。一个阀门表示一个特定的任务,在任务流中有一个最基本的阀门,同时你也可以根据需要任意添加阀门,阀门的数目定义为添加的阀门的个数(不包括基本阀门)。阀门可以通过编辑server.xml来自己添加。
如果你已经理解了servlet过滤器,那么任务流和它的阀门的工作方式不难想象。任务流就像过滤器链而阀门就像过滤器,跟过滤器一样,一个阀门可以操作传递给它的 request 和 response 方法。让一个阀门完成了处理,则进一步处理流水线中的下一个阀门,基本阀门总是在最后才被调用。
一个容器可以有一个流水线。当容器的 invoke 方法被调用的时候,容器将会处理流水线中的阀门,并一个接一个的处理,直到所有的阀门都被处理完毕。可以想象流水线的 invoke 方法的伪代码如下所示:
// 执行添加的阀门
for (int n=0; n<valves.length; n++) {
valve[n].invoke( ... );
}
// 执行基本阀门
basicValve.invoke( ... );
但是, Tomcat 的设计者选择了一种不同的通过org.apache.catalina.valves.ValveBase定义的方式来处理,在org.apache.catalina.valves包下,定义了各种不同的valves.他们继承自ValveBase,实现Valve中的invoke方法。在创建一个Valve对象之后,阀门调用getNext继续执行下一个方法。
现在来看看各接口的细节:
The Pipeline Interface 任务流接口
public interface Pipeline
{
public Valve getBasic();
public void setBasic(Valve paramValve);
public void addValve(Valve paramValve);
public Valve[] getValves();
public void removeValve(Valve paramValve);
public Valve getFirst();
public boolean isAsyncSupported();
public Container getContainer();
public void setContainer(Container paramContainer);
}
The Valve Interface 阀门接口
public interface Valve
{
public Valve getNext();
public void setNext(Valve paramValve);
public void backgroundProcess();
public void invoke(Request paramRequest, Response paramResponse)
throws IOException, ServletException;
public boolean isAsyncSupported();
}
The Contained Interface
一个阀门可以选择性的实现 org.apache.catalina.Contained 接口。该接口定义了其实现类跟一个容器相关联
public interface Contained
{
public Container getContainer();
public void setContainer(Container paramContainer);
}
Wrapper接口
org.apache.catalina.Wrapper 接口表示了一个包装器。一个包装器是表示一个独立 servlet 定义的容器。包装器继承了 Container 接口,并且加了几个方法,包装器的实现类负责管理其下层 servlet 的生命周期,包括 servlet 的init,service,和 destroy 方法。由于包装器是最底层的容器,所以不可以将子容器添加给它。
包装器接口中重要方法有 allocate 和 load 方法。 allocate 方法负责定位该包装器表示的 servlet 的实例。 Allocate 方法必须考虑一个 servlet 是否实现了javax.servlet.SingleThreadModel 接口,该部分内容将会在 11 章中进行讨论。Load 方法负责 load 和初始化 servlet 的实例。
Context接口
一个 context 在容器中表示一个 web 应用。一个 context 通常含有一个或多个包装器作为其子容器。重要的方法包括addWrapper,createWrapper 等方法。
更多推荐
所有评论(0)