How Tomcat Works(八)
下面接着分析Context容器,该接口最重要的方法是addWrapper()方法与creatWrapper()方法,添加具体的子容器,这里是Wrapper容器实例
这里要分析的是一个简单的Context容器,它针对特定的客户端请求,通过映射器找到要处理该特定请求的子容器实例(Wrapper)
具体流程是,Context容器首先调用额外的阀,最后调用基础阀(这里是SimpleContextValve),在基础阀里面通过映射器找到要 处理该请求的子容器Wrapper实例,然后再调用子容器Wrapper实例的各个阀(本示例的Wrapper只有基础阀)(类似于composte模式 迭代)
下面是SimpleContext类的实现,SimpleContext实现org.apache.catalina.Context接口和org.apache.catalina.Pipeline接口
public class SimpleContext implements Context, Pipeline { public SimpleContext() {
pipeline.setBasic(new SimpleContextValve());
} // 子容器名称与子容器实例映射
protected HashMap children = new HashMap();
protected Loader loader = null;
protected SimplePipeline pipeline = new SimplePipeline(this);
// servlet模式与子容器名称映射
protected HashMap servletMappings = new HashMap();
// 映射器
protected Mapper mapper = null;
// 映射器协议与映射器实例映射
protected HashMap mappers = new HashMap();
private Container parent = null; /**
* 添加servlet模式与子容器名称(wrapper)到HashMap servletMappings容器
* @param pattern
* @param name
*/
public void addServletMapping(String pattern, String name) {
synchronized (servletMappings) {
servletMappings.put(pattern, name);
}
} /**
* 根据servlet模式找到对应的子容器名称(wrapper)(供映射器调用)
* @param pattern
* @return
*/
public String findServletMapping(String pattern) {
synchronized (servletMappings) {
return ((String) servletMappings.get(pattern));
}
} /**
* 获取加载器
* @return
*/
public Loader getLoader() {
if (loader != null)
return (loader);
if (parent != null)
return (parent.getLoader());
return (null);
} /**
* 设置加载器
* @param loader
*/
public void setLoader(Loader loader) {
this.loader = loader;
} /**
* 添加子容器实例(wrapper)名称与子容器实例(wrapper)到HashMap children容器
* @param child
*/
public void addChild(Container child) {
child.setParent((Container) this);
children.put(child.getName(), child);
} /**
* 根据名称查找子容器实例wrapper(供映射器调用)
* @param name
* @return
*/
public Container findChild(String name) {
if (name == null)
return (null);
synchronized (children) {
// Required by post-start changes
return ((Container) children.get(name));
}
} /**
* 查找子容器数组
* @return
*/
public Container[] findChildren() {
synchronized (children) {
Container results[] = new Container[children.size()];
return ((Container[]) children.values().toArray(results));
}
} /**
* 添加映射器实例
* @param mapper
*/
public void addMapper(Mapper mapper) {
// this method is adopted from addMapper in ContainerBase
// the first mapper added becomes the default mapper
mapper.setContainer((Container) this); // May throw IAE
this.mapper = mapper;
synchronized (mappers) {
if (mappers.get(mapper.getProtocol()) != null)
throw new IllegalArgumentException("addMapper: Protocol '"
+ mapper.getProtocol() + "' is not unique");
mapper.setContainer((Container) this); // May throw IAE
mappers.put(mapper.getProtocol(), mapper);
if (mappers.size() == 1)
this.mapper = mapper;
else
this.mapper = null;
}
} /**
* 根据协议查找映射器实例
* @param protocol
* @return
*/
public Mapper findMapper(String protocol) {
// the default mapper will always be returned, if any,
// regardless the value of protocol
if (mapper != null)
return (mapper);
else
synchronized (mappers) {
return ((Mapper) mappers.get(protocol));
}
} public Mapper[] findMappers() {
return null;
} /**
* 根据请求找到子容器实例wrapper (供基础阀调用该方法)
* @param request
* @param update
* @return
*/
public Container map(Request request, boolean update) {
// this method is taken from the map method in
// org.apache.cataline.core.ContainerBase
// the findMapper method always returns the default mapper, if any,
// regardless the
// request's protocol
Mapper mapper = findMapper(request.getRequest().getProtocol());
if (mapper == null)
return (null); // Use this Mapper to perform this mapping
// 具体过程 (回调该对象下面方法)
// 根据request找到处理该请求的子容器wrapper名称 调用方法 String findServletMapping(String pattern)
// 根据上面的子容器wrapper名称找到子容器wrapper 调用方法 Container findChild(String name)
return (mapper.map(request, update));
} public void invoke(Request request, Response response) throws IOException,
ServletException {
pipeline.invoke(request, response);
} // method implementations of Pipeline
public Valve getBasic() {
return pipeline.getBasic();
} public void setBasic(Valve valve) {
pipeline.setBasic(valve);
} public synchronized void addValve(Valve valve) {
pipeline.addValve(valve);
} public Valve[] getValves() {
return pipeline.getValves();
} public void removeValve(Valve valve) {
pipeline.removeValve(valve);
} }
下面我们来分析映射器SimpleContextMapper的实现
public class SimpleContextMapper implements Mapper { /**
* The Container with which this Mapper is associated.
*/
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) {
} /**
* Return the child Container that should be used to process this Request,
* based upon its characteristics. If no such child Container can be
* identified, return <code>null</code> instead.
*
* @param request Request being processed
* @param update Update the Request to reflect the mapping selection?
*
* @exception IllegalArgumentException if the relative portion of the
* path cannot be URL decoded
*/
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);
}
}
映射器SimpleContextMapper最重要的方法是Container map(Request request, boolean update)
即根据客户端请求找到对应的子容器实例wrapper,里面关键代码是回调context容器实例的方法(持有对SimpleContext实例的引用)
接下里分析基础阀的关键代码(管道持有对基础阀的引用)
public class SimpleContextValve implements Valve, Contained { protected Container container; 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; // NOTE - Not much else we can do generically
} // 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);
} public Container getContainer() {
return container;
} public void setContainer(Container container) {
this.container = container;
} private void badRequest(String requestURI, HttpServletResponse response) {
try {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, requestURI);
}
catch (IllegalStateException e) {
;
}
catch (IOException e) {
;
}
} private void notFound(String requestURI, HttpServletResponse response) {
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI);
}
catch (IllegalStateException e) {
;
}
catch (IOException e) {
;
}
} }
基础阀持有对Context容器实例(SimpleContext)的引用,在它的关键方法void invoke(Request request, Response response, ValveContext valveContext)里面,先调用Context容器实例的Container map(Request request, boolean update)方法获取子容器实例wrapper,最后调用子容器实例wrapper的invoke(Request request, Response response)方法
至于管道类SimplePipeline与上文相同,此处不再描述
---------------------------------------------------------------------------
本系列How Tomcat Works系本人原创
转载请注明出处 博客园 刺猬的温驯
本人邮箱: chenying998179#163.com (#改为@)
本文链接 http://www.cnblogs.com/chenying99/p/3235730.html
How Tomcat Works(八)的更多相关文章
- How Tomcat works — 八、tomcat中的session管理
在使用shiro的session的时候感觉对于tomcat中session的管理还不是特别清楚,而且session管理作为tomcat中比较重要的一部分还是很有必要学习的. 目录 概述 session ...
- How Tomcat Works(十八)
在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...
- How Tomcat Works(二十)
要使用一个web应用程序,必须要将表示该应用程序的Context实例部署到一个host实例中.在tomcat中,context实例可以用war文件的形式来部署,也可以将整个web应用拷贝到Tomcat ...
- 攻城狮在路上(肆)How tomcat works(零) 前言说明
最近几篇是关于How tomcat works一书的读书笔记. 通过数个章节逐渐实现一个tomcat的功能. 源码下载地址:http://zhidao.baidu.com/share/7007af0f ...
- How Tomcat works — 四、tomcat启动(3)
上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看conta ...
- How Tomcat Works(十四)补充
在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...
- How Tomcat Works(十七)
在前面的文章中,已经学会了如何通过实例化一个连接器和容器来获得一个servlet容器,并将连接器和容器相关联:但在前面的文章中只有一个连接器可用,该连接器服务8080端口上的HTTP请求,无法添加另一 ...
- How Tomcat Works(十六)
本文接下来会介绍Host容器和Engine容器,在tomcat的实际部署中,总是会使用一个Host容器:本文介绍Host接口和Engine接口及其相关类 Host容器是org.apache.catal ...
- How Tomcat Works(十五)
本文接下来分析Context容器,Context容器实例表示一个具体的Web应用程序,其中包括一个或多个Wrapper实例:不过Context容器还需要其他的组件支持,典型的如载入器和Session管 ...
随机推荐
- 报错:对象必须实现 IConvertible;以分隔符进行分割链接concat_ws的使用方法;mysql数据类型转换cast,convert
错误故障,mysql 服务器上用 concat_ws 函数,连接了一串数字,最后 服务器返回的字段就变成了一个 byte ,而我们想要的类型是 string 类型,那么转换的时候,就报错了. 正确 ...
- 代码记录:使用Aforge.net让视频图像反转180度
private void CameraConn() { videoSource = new VideoCaptureDevice(videoDevices[tscbxCameras.SelectedI ...
- android studio 加载第三方类库
以引入Xutil包为例 1. 将Xutil包导入到module的libs目录下 2. File->project structure 还有一种方法是在libs目录下右键点击Add as libr ...
- 20160201.CCPP体系详解(0011天)
内容概要:C语言基本数据类型及运算题库(含答案) 第二章 基本数据类型及运算 一.选择题 1. 若以下选项中的变量已正确定义,则正确的赋值语句是[C]. A) x1=26.8%3; B) 1+2=x2 ...
- OGNL valueStack StackContext(ActionContext)深入分析(转+个人理解)
//还会补充 首先要有一个意识 ,为什么要了解这个?: struts2中的表单是怎么通过表达式(EL or OGNL)来传给Action 和 拿到Action的值的. 值栈(根)对象也可以直接使用EL ...
- php的setcookie
不同浏览器对cookie的原理不同,导致cookie的过期时间有些模糊. 经测试:火狐浏览器的cookie过期时间设置是根据增量原则.服务器端设置time()+num,或者time()-num,传递到 ...
- 【英语】Bingo口语笔记(79) - fish系列
- Mysql事物与Metadata lock 问题
环境说明: MySQL 5.6.16 OS:Linux RedHat 6.2 64bit 1.问题描述 目前新上一个使用MySQL数据库项目,在数据库中,每隔5分钟做truncate某 ...
- 查看Linux下端口占用情况的命令
在使用Linux系统的过程中,有时候会遇到端口被占用而导致服务无法启动的情况.比如HTTP使用80端口,但当启动Apache时,却发现此端口正在使用. 这种情况大多数是由于软件冲突.或者默认端口设置不 ...
- Hadoop学习总结之五:Hadoop的运行痕迹
Hadoop学习总结之五:Hadoop的运行痕迹 Hadoop 学习总结之一:HDFS简介 Hadoop学习总结之二:HDFS读写过程解析 Hadoop学习总结之三:Map-Reduce入门 Ha ...