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

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

[复制链接]

尚未签到

发表于 2017-2-6 13:02:22 | 显示全部楼层 |阅读模式
The Context Application
这章的第一个应用,你了解了怎么部署一个只有一个wrapper组成的简单的web应用程序。这个应用中只有一个servlet。在一个应用中,只要一个单独的servlet是可能的,但大多数情况下需要更多。在这种情况下,你需要和wrapper相比不同的容器类型。你就需要一个context。
第二个应用程序演示了怎么使用一个有两个wrapper的context,context包装了两个servlet类。当有多于一个wrapper的时候,你就需要用到一个映射器(mapper)。mapper它是一个帮助容器(本例中是context)选择一个子容器来处理特定的请求的组件。
注意一个mapper只能在Tomcat 4中找到,在Tomcat 5中使用另外一种方式找到一个子容器。
mapper是ex05.pyrmont.core.SimpleContextMapper类的实例,它实现org.apache.catalina.Mapper接口。
一个容器也使用多个mapper来支持多协议。这种情况下,一个mapper支持一种请求协议。例如:一个容器可能有一个为HTTP协议的mapper,另外一个是HTTPS协议的mapper。

Listing 5.13: The Mapper interface   
package org.apache.catalina;
public interface Mapper {
public Container getContainer();
public void setContainer(Container container);
public String getProtocol();
public void setProtocol(String protocol);
public Container map(Request request, boolean update);
}

getContainer方法返回与mapper相关联的容器,setContainer方法是用来把一个mapper和一个容器相关联。getProtocal方法返回这个mapper负责处理的协议,setProtocol方法用来指配这个mapper负责处理的协议的名字。map方法返回一个用来处理特定的请求的子容器。
类图:
DSC0000.jpg
SimpleContext类代表一个context。它使用SimpleContextMapper作为它的mapper,SimpleContextValve作为basic valve。两个valve:ClientIPLoggerValve 和HeaderLoggerValve
被添加到context。两个wrapper,用SimpleWrapper代表,被作为子容器添加到context。
wrapper使用SimpleWrapperValve作为它们的basic valve,但是没有其他的valve。
Context应用程序使用相同的loader和两个valve。但是loader和valve是和context相关联的,而不是和wrapper相关联。这样,loader可以被所有的wrapper使用。context被指配为一个连接器的容器。此外,连接器在收到一个HTTP请求时将调用context的invoke方法。
1:一个容器有一个pipeline。容器的invoke方法调用pipeline的invoke方法。
2:pipeline的invoke方法调用所有的添加在容器里的valve。然后调用它的basic valve的invoke方法。
3:在一个wrapper中,basic valve负责加载相关联的servlet和相关request。
4:在一个有子容器的context中,basic valve使用mapper来找到一个负责处理请求的子容器。如果一个子容器被找到,它调用子容器的invoke方法,然后返回第一步。
现在看看在实现中的处理:
SimpleContext类的invoke方法调用pipeline的invoke方法:

The SimpleContext class's invoke method calls the pipeline's invoke method.
public void invoke(Request request, Response response)
throws IOException, ServletException {
pipeline.invoke(request, response);
}

pipeline是由SimplePipeline类代表。它的invoke方法:

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);
}

SimpleContextValve使用context的mapper找到wrapper:

// Select the Wrapper to be used for this Request
Wrapper wrapper = null;
try {
wrapper = (Wrapper) context.map(request, true);
}

如果找到一个wrapper,它的invoke方法将被调用。

wrapper.invoke(request, response);

一个应用程序中的wrapper是SimpleWrapper类代表的。这里invoke方法:

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

这个pipeline是一个SimplePipeline的实例。这个wrapper除了basic valve(SimpleArapperValve的实例)就没有其他valve。wrapper的pipeline调用SimpleWrapperValve类的invoke方法来分配servlet,调用它的service方法。
注意wrapper和一个loader是不相关联的,但是和context是相关联的。SimpleWrapper类的getLoader方法返回父类的loader。
SimpleContext, SimpleContextValve, SimpleContextMapper和Bootstrap2
ex05.pyrmont.core.SimpleContextValve
这个类代表SimpleContext的basic valve。它的重要方法:invoke:

public void invoke(Request request, Response response,ValveContext valveContext)
throws IOException, ServletException {
// Validate the request and response object types
if (!(request.getRequest() instanceof HttpServletRequest) ||
!(response.getResponse() instanceof HttpServletResponse)) {
return;
}
// Disallow any direct access to resources under WEB-INF or META-INF
HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
String contextPath = hreq.getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length()).toUpperCase();
Context context = (Context) getContainer();
// Select the Wrapper to be used for this Request
Wrapper wrapper = null;
try {
wrapper = (Wrapper) context.map(request, true);
}catch (IllegalArgumentException e) {
badRequest(requestURI, (HttpServletResponse)
response.getResponse());
return;
}
if (wrapper == null) {
notFound(requestURI, (HttpServletResponse) response.getResponse());
return;
}
// Ask this Wrapper to process this Request
response.setContext(context);
wrapper.invoke(request, response);
}


ex05.pyrmont.core.SimpleContextMapper
SimpleContextMapper类,实现了org.apache.catalina.Mapper接口。

Listing 5.15: The SimpleContextMapper class   
package ex05.pyrmont.core;
import javax.servlet.http.HttpServletRequest;
import org.apache.catalina.Container;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.Mapper;
import org.apache.catalina.Request;
import org.apache.catalina.Wrapper;
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) {
// Identify the context-relative URI to be mapped
String contextPath = ((HttpServletRequest) request.getRequest()).getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length());
// Apply the standard request URI mapping rules from
// the specification
Wrapper wrapper = null;
String servletPath = relativeURI;
String pathInfo = null;
String name = context.findServletMapping(relativeURI);
if (name != null)
wrapper = (Wrapper) context.findChild(name);
return (wrapper);
}
}

SetContainer方法当在你如果传递的一个容器不是SimpleContext的实例,它将抛出一个IllegalArgumentException异常。map方法返回一个子容器(wrapper)负责来处理请求。map方法有两个参数,一个request对象和一个boolean值。实现将忽略第二个参数。这个方法是从请求对象中获取context路径和使用context的findServletMapping方法获取相关的路径名。如果一个路径名被找到,它使用context的findChild方法获取一个Wrapper的实例。
ex05.pyrmont.core.SimpleContext
SimpleContext类是context的实现。它是与连接器相关联的主容器。但是处理每一个单独的servlet是wraper完成的。这个应用有两个servlet:PrimitiveServlet 和ModernServlet。每一个wrapper有一个名字。PrimitiveServlet 的wrapper名字是Primitive,ModernServlet的wrapper的名字是Morden。SimpleContext决定哪一个wrapper将被调用来处理每一个请求。你必须映射请求URL和wrapper的名字。这个应用中,我们有两个URL可以用来调用两个wrapper。第一个是/Primitive,是用来映射到wrapper Primitive。第二个是/Modern,是映射到wrapper Modern。
这里有很多Container和Context接口的方法在SimpleContext中必须实现。大多方法是空方法。
addServletMapping:增加一个URL/wrapper名字对。你每增加一个URL就可以用给出的相应的名字来调用这个wrapper。
findServletMapping:获取给出的URL对应的wrapper的名字。这个方法用来找到哪个wrapper应该被某个特定的URL调用。如果给出的URL没有使用addServletMapping方法来注册,这个方法就返回null。
addMapper:给context增加一个mapper。SimpleContext类声明了mapper变量和mappers变量。mapper是指默认mapper,而mappers包含所有SimpleContext实例的mapper。第一个增加到context的mapper就是默认的mapper。
findMapper:找到正确的mapper。在SimpleContext,它返回默认mapper。
Map:返回负责处理这个请求的wrapper。
此外,SimpleContext也提供addChild、findChild和findChildren方法的实现。addChild方法用来把一个wrapper添加到context中,findChild方法通过名字来找到一个wrapper,findChildren方法返回SimpleContext中的所有wrapper实例。
ex05.pyrmont.startup.Bootstrap2

Listing 5.16: The Bootstrap2 class   
package ex05.pyrmont.startup;
import ex05.pyrmont.core.SimpleContext;
import ex05.pyrmont.core.SimpleContextMapper;
import ex05.pyrmont.core.SimpleLoader;
import ex05.pyrmont.core.SimpleWrapper;
import ex05.pyrmont.valves.ClientIPLoggerValve;
import exO5.pyrmont.valves.HeaderLoggerValve;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Loader;
import org.apache.catalina.Mapper;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina Wrapper;
import org.apache.catalina.connector.http.HttpConnector;
public final class Bootstrap2 {
public static void main(String[] args) {
HttpConnector connector = new HttpConnector();
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);
Valve valve1 = new HeaderLoggerValve();
Valve valve2 = new ClientIPLoggerValve();
((Pipeline) context).addValve(valve1);
((Pipeline) context).addValve(valve2);
Mapper mapper = new SimpleContextMapper();
mapper.setProtocol("http");
context.addMapper(mapper);
Loader loader = new SimpleLoader();
context.setLoader(loader);
// context.addServletMapping(pattern, name);
context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");
connector.setContainer(context);
try {
connector.initialize();
connector.start();
// make the application wait until we press a key.
System.in.read();
} catch (Exception e) {
e.printStackTrace();
}
}
}

主方法开始实例化Tomcat默认连接器和两个wrapper:wrapper1和wrapper2。

HttpConnector connector = new HttpConnector();
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");  
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");

然后,主方法创建一个SimpleContext的实例,添加wrapper1和wrapper2作为SimpleContext的容器的子容器,实例化两个valveClientIPLoggerValve和 HeaderLoggerValve,
并把他们两个valve添加到SimpleContext。

Context context = new SimpleContext();
context.addChild(wrapper1);
context.addChild(wrapper2);
Valve valve1 = new HeaderLoggerValve();
Valve valve2 = new ClientIPLoggerValve();
((Pipeline) context).addValve(valve1);
((Pipeline) context).addValve(valve2);

接下来它构建一个mapper对象,并把mapper添加到SimpleContext。mapper负责找到在context里的子容器,让其来处理HTTP请求。

Mapper mapper = new SimpleContextMapper();
mapper.setProtocol("http");
context.addMapper(mapper);

加载servlet类,你需要一个loader。这里你使用SimpleLoader类,就像第一个应用程序一样。但是,不同时是增加两个wrapper,loader被添加到context里。wrapper将使用getLoader方法找到loader,因为context是他们的父容器。

Loader loader = new SimpleLoader();
context.setLoader(loader);

现在,该添加servlet映射了。为你添加的两个wrapper作映射。

// context.addServletMapping(pattern, name);
context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");

最后,把context作为容器指配给连接器,初始化并启动连接器。

connector.setContainer(context);
try {
connector.initialize();
connector.start();

                                                      第五章 完

运维网声明 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-338413-1-1.html 上篇帖子: Tomcat请求处理(七) 下篇帖子: tomcat下面cocoon-2.1.16安装过程中容易出现的两个错误及解决办法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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