设为首页 收藏本站
查看: 472|回复: 0

[经验分享] Coder 爱翻译 How Tomcat Works 第五章 第一部分

[复制链接]
YunVN网友  发表于 2017-2-4 13:44:26 |阅读模式
Chapter 5: Container
一个容器是一个为servlet处理请求和给客户端填充response对象的模块。一个容器可以用
org.apache.catalina.Container接口表示。这里有四种类型的容器:Engine, Host, Context 和Wrapper。这章包含了Context和Wrapper。把其它两个容器放在后面第十三章讲解。
The Container Interface
一个容器必须实现了org.apache.catalina.Container。你看到了在第四章中,你传递一个Container实例给连接器的toContainer方法,这样连接器可以调用容器的invoke方法。回顾下面的Bootstrap类的代码:

HttpConnector connector = new HttpConnector();
SimpleContainer container = new SimpleContainer();
connector.setContainer(container);

第一件要注意的事情是在Catalina里面的容器在不同概念层次上的划分有下面四种类型的容器:
Engine:
Represents the entire Catalina servlet engine. (代表整个Catalina的servlet engine)
Host:
Represents a virtual host with a number of contexts.(代表一个有许多context的虚拟主机)
Context:
Represents a web application. A context contains one or more wrappers.(代表一个web应用,一个context包含一个或更多wrapper)
Wrapper:
Represents an individual servlet.(代表一个单独的servlet)
每个概念上的层次用org.apache.catalina包中的一个接口表示。这些接口是:Engine, Host, Context和 Wrapper。这四个接口都继承了Container接口。这四个容器的标准实现分别是:
StandardEngine, StandardHost, StandardContext和StandardWrapper。很具有代表性,他们都是org.apache.catalina.core包的一部分。
一个能完成应用功能的Catalina的部署不需要包含所有的这四种容器。例如:在这章的第一个应用程序的容器模块只包含了一个wrapper。第二个应用程序是一个拥有一个context和一个wrapper的容器模块。这章的应用程序中既没有host也没有engine。
一个容器可以有0个或更多低层次的的子容器。例如:一个context通常有一个或更多wrapper,一个host可以有0个或更多context。但是,一个wrapper是位于层次结构的最底层,他就不能包含子容器。增加一个子容器到一个容器中,你使用Container接口的addChild方法:

public void addChild(Container child);

从一个容器中移除一个子容器使用Container接口的removeChild方法:

public void removeChild(Container child);

此外,Container接口支持使用findChild和FindChildren方法找到一个容器的一个子容器和一个容器的所有子容器集合:

public Container findChild(String name);
public Container[] findChildren();

一个容器也可以包含很多个像后面要讲到的支持组件:Loader, Logger, Manager, Realm和Resources.这里不得不提一下Container接口提供的get和set方法来把容器自己和组件联系起来的方法:getLoader 和setLoader, getLogger 和setLogger, getManager 和
setManager, getRealm 和setRealm,getResources 和 setResources。
更有趣的是,Container接口通过这种方式来指定:在部署的时候,一个Tomcat的管理员(administrator)通过修改配置文件(server.xml)决定一个容器是完成什么事情的。而这又是通过在一个容器中引入一个pipeline和一套valve来实现的。
注意:Tomcat 4 的Container接口和Tomcat 5的稍有一点不同。例如:Tomcat 4 接口有一个map方法,而在Tomcat 5中就没有。
Pipelining Tasks
一个pipeline包含了容器将要调用的任务(tasks)。一个valve代表一个具体的任务。一个容器的pipeline有一个(basic valve)基本的valve(阀),但是你还是可以添加任意多你想要添加的valve。valve的数量是由增加的valve的数量决定,但不包含basic valve。有趣的是,valve可以通过修改Tomcat的配置文件(server.xml)来动态地添加。
如果你了解servlet的filter,你就不难想象一个pipeline的valve是怎么工作的了。一个pipeline就像是一个filter chain,而每一个valve就是一个filter。就像filter一样,一个valve可以处理传递给它的request和response对象。当一个valve完成了处理工作,它就调用在pipeline中的下一个valve。而basic valve总是在最后被调用。
一个容器可以有一个pipeline。当一个容器的invoke方法被调用,容器传递处理任务到它的pipeline,这个pipeline就调用它的第一个valve,然后调用它后面的valve,依次调用到最后。
直到在pipeline中再也没有valve。你可以想象的到,你可以跟着下面的pipeline的invoke方法的伪代码:

// invoke each valve added to the pipeline
for (int n=0; n<valves.length; n++) {
valve[n].invoke( ... );
}
// then, invoke the basic valve
basicValve.invoke( ... );

但是,Tomcat的设计者选择了不同的方式,通过引入了org.apache.catalina.ValveContext接口。下面介绍它怎么工作的。
一个容器当它的invoke方法被连接器调用时,它打算做什么事情不能通过(hard code)硬编码实现。而是容器调用它的pipeline的invoke方法。Pipeline接口的invoke方法和Container接口的invoke方法相同:

public void invoke(Request request, Response response)
throws IOException, ServletException;

下面是Container接口的invoke方法在org.apache.catalina.core.ContainerBase类的实现

public void invoke(Request request, Response response)
throws IOException, ServletException {
pipeline.invoke(request, response);
}

pipeline是容器内部的Pipeline接口的实例。
现在,pipeline必须确认所有的valve被添加,basic valve必须被调用一次。pipeline通过创建一个ValveContext接口的实例来完成valve的添加确认。ValveContext是作为一个pipeline的内部类实现的,所以ValveContext可以访问pipeline的所有成员。ValveContext接口的最重要的方法是invokeNext方法:

public void invokeNext(Request request, Response response)
throws IOException, ServletException

创建了一个ValveContext实例后,pipeline调用ValveContext的invokeNext方法。ValveContext将首先调用pipeline中的第一个valve,然后第一个valve在它完成了任务前将调用下一个valve。ValveContext把它自己传递给每一个valve,所以valve可以调用ValveContext的invokeNext方法。

public void invoke(Request request, Response response,
ValveContext ValveContext) throws IOException, ServletException

一个valve的invoke方法的实现:

public void invoke(Request request, Response response,
ValveContext valveContext) throws IOException, ServletException {
// Pass the request and response on to the next valve in our pipeline
valveContext.invokeNext(request, response);
// now perform what this valve is supposed to do
...
}

org.apache.catalina.core.StandardPipeline类是在所有容器的Pipeline的实现。在Tomcat 4中,这个类有一个叫做StandardPipelineValveContext的实现了ValveContext接口的内部类。

Listing 5.1: The StandardPipelineValveContext class in Tomcat 4   
protected class StandardPipelineValveContext implements ValveContext {
protected int stage = 0;
public String getInfo() {
return info;
}
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
(sm.getString("standardPipeline.noValve"));
}
}
}

invokeNext方法使用下标(subscript)和状态(stage)来明确指出哪一个valve被调用过。当在pipeline的invoke方法第一个valve被调用时,下标值是0,状态值是1。因此,第一个valve(数组下标是0)被调用。在pipeline中的第一个valve接收ValveContext实例和调用它的invokeNext方法。这时,下标值是1,当然第二个valve被调用,以此类推。
当最后一个valve的invokeNext方法被调用时,下标值是等于valve的数量。最后,basic valve被调用。
Tomcat 5从StandardPipeline中移除了StandardPipelineValveContext类,而依靠org.apache.catalina.core.StandardValveContext。

Listing 5.2: The StandardValveContext class in Tomcat 5   
package org.apache.catalina.core;
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.Valve;
import org.apache.catalina.ValveContext;
import org.apache.catalina.util.StringManager;
public final class StandardValveContext implements ValveContext {
protected static StringManager sm =  StringManager.getManager(Constants.Package);
protected String info =  "org.apache.catalina.core.StandardValveContext/1.0";
protected int stage = 0;
protected Valve basic = null;
protected Valve valves[] = null;
public String getInfo() {
return info;
}
public final 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
(sm.getString("standardPipeline.noValve"));
}
}
void set(Valve basic, Valve valves[]) {
stage = 0;
this.basic = basic;
this.valves = valves;
}
}

你可以看见Tomcat 4中的StandardPipelineValveContext类和Tomcat 5 中的StandardValveContext类相似。
下面们将要详细讨论Pipeline, Valve和 ValveContext接口:

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-337499-1-1.html 上篇帖子: eclipse下tomcat发布失败(Could not delete May be locked by another process)(转) 下篇帖子: tomcat JAVA启动参数 JAVA_OPTS OutOfMemoryError[转贴]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表