How Tomcat Works(十六)
本文接下来会介绍Host容器和Engine容器,在tomcat的实际部署中,总是会使用一个Host容器;本文介绍Host接口和Engine接口及其相关类
Host容器是org.apache.catalina.Host接口的实例,Host接口继承自Container接口, 其定义如下
public interface Host extends Container {
public static final String ADD_ALIAS_EVENT = "addAlias";
public static final String REMOVE_ALIAS_EVENT = "removeAlias";
public String getAppBase();
public void setAppBase(String appBase);
public boolean getAutoDeploy();
public void setAutoDeploy(boolean autoDeploy);
public void addDefaultContext(DefaultContext defaultContext);
public DefaultContext getDefaultContext();
public String getName();
public void setName(String name);
public void importDefaultContext(Context context);
public void addAlias(String alias);
public String[] findAliases();
public Context map(String uri);
public void removeAlias(String alias);
}
该接口中比较重要的方法是map()方法,该方法返回一个用来处理引入的HTTP请求的Context容器的实例,该方法的具体实现在StandardHost类中
在tomcat中org.apache.catalina.core.StandardHost类是Host接口的标准实现,该类继承自org.apache.catalina.core.ContainerBase类,实现了Host和Deployer接口
与StandardContext类和StandardWrapper类相似,StandardHost类的构造函数会将一个基础阀的实例添加到其管道对象中:
public StandardHost() {
super();
pipeline.setBasic(new StandardHostValve());
}
基础阀是org.apache.catalina.core.StandardHostValve类的实例
当调用其start()方法时,StandardHost实例会添加两个阀,分别为ErrorReportValve类和ErrorDispatcherValve类的实例,这两个阀均位于org.apache.catalina.valves包下
public synchronized void start() throws LifecycleException {
// Set error report valve
if ((errorReportValveClass != null)
&& (!errorReportValveClass.equals(""))) {
try {
Valve valve = (Valve) Class.forName(errorReportValveClass)
.newInstance();
addValve(valve);
} catch (Throwable t) {
log(sm.getString
("standardHost.invalidErrorReportValveClass",
errorReportValveClass));
}
}
// Set dispatcher valve
addValve(new ErrorDispatcherValve());
super.start();
}
每当引入一个HTTP请求,都会调用Host实例的invoke()方法,这里是StandardHost的父类ContainerBase类的invoke()方法,而ContainerBase类的invoke()方法会调用StandardHost实例的基础阀StandardHostValve实例的invoke()方法;StandardHostValve类的invoke()方法会调用StandardHost类的map()方法来获取相应的Context实例来处理HTTP请求
public Context map(String uri) {
if (debug > 0)
log("Mapping request URI '" + uri + "'");
if (uri == null)
return (null);
// Match on the longest possible context path prefix
if (debug > 1)
log(" Trying the longest context path prefix");
Context context = null;
String mapuri = uri;
while (true) {
context = (Context) findChild(mapuri);
if (context != null)
break;
int slash = mapuri.lastIndexOf('/');
if (slash < 0)
break;
mapuri = mapuri.substring(0, slash);
}
// If no Context matches, select the default Context
if (context == null) {
if (debug > 1)
log(" Trying the default context");
context = (Context) findChild("");
}
// Complain if no Context has been selected
if (context == null) {
log(sm.getString("standardHost.mappingError", uri));
return (null);
}
// Return the mapped Context (if any)
if (debug > 0)
log(" Mapped to context '" + context.getPath() + "'");
return (context);
}
在tomcat4中, StandardHost的父类ContainerBase类会调用其addDefaultMapper()方法创建一个默认映射器,默认映射器的类型由mapperClass属性的值决定
protected void addDefaultMapper(String mapperClass) {
// Do we need a default Mapper?
if (mapperClass == null)
return;
if (mappers.size() >= 1)
return;
// Instantiate and add a default Mapper
try {
Class clazz = Class.forName(mapperClass);
Mapper mapper = (Mapper) clazz.newInstance();
mapper.setProtocol("http");
addMapper(mapper);
} catch (Exception e) {
log(sm.getString("containerBase.addDefaultMapper", mapperClass),
e);
}
}
变量mapperClass的值定义在StandardHst类中
private String mapperClass =
"org.apache.catalina.core.StandardHostMapper";
在tomcat4中,StandardHost类的start()方法会在方法末尾调用addDefaultMapper()方法,确保默认映射器的创建完成
当然,StandardHostMapper类中最重要的方法是map()方法,下面是map()方法的实现
public Container map(Request request, boolean update) {
// Has this request already been mapped?
if (update && (request.getContext() != null))
return (request.getContext());
// Perform mapping on our request URI
String uri = ((HttpRequest) request).getDecodedRequestURI();
Context context = host.map(uri);
// Update the request (if requested) and return the selected Context
if (update) {
request.setContext(context);
if (context != null)
((HttpRequest) request).setContextPath(context.getPath());
else
((HttpRequest) request).setContextPath(null);
}
return (context);
}
注意,这里map()方法仅仅是简单地调用了Host实例的map()方法
org.apache.catalina.core.StandardHostValve类是StandardHost实例的基础阀,当有引入的HTTP请求时,会调用StandardHostValve类的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; // NOTE - Not much else we can do generically
} // Select the Context to be used for this Request
StandardHost host = (StandardHost) getContainer();
Context context = (Context) host.map(request, true);
if (context == null) {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
sm.getString("standardHost.noContext"));
return;
} // Bind the context CL to the current thread
Thread.currentThread().setContextClassLoader
(context.getLoader().getClassLoader()); // Update the session last access time for our session (if any)
HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
String sessionId = hreq.getRequestedSessionId();
if (sessionId != null) {
Manager manager = context.getManager();
if (manager != null) {
Session session = manager.findSession(sessionId);
if ((session != null) && session.isValid())
session.access();
}
} // Ask this Context to process this request
context.invoke(request, response); }
在tomcat4中,invoke()方法会调用StandardHost实例的map()方法获取一个相应的Context实例;然后获取与该request对象相关联的session对象,并调用其access()方法,access()方法会修改session对象的最后访问时间;最后调用Context实例的invoke()来处理HTTP请求
接下来描述Engine容器,Engine容器是org.apache.catalina.Engine接口的实例,Engine容器也就是Tomcat的servlet引擎
public interface Engine extends Container {
public String getDefaultHost();
public void setDefaultHost(String defaultHost);
public String getJvmRoute();
public void setJvmRoute(String jvmRouteId);
public Service getService();
public void setService(Service service);
public void addDefaultContext(DefaultContext defaultContext);
public DefaultContext getDefaultContext();
public void importDefaultContext(Context context);
}
在Engine容器中,可以设置一个默认的Host容器或一个默认的Context容器,注意,Engine容器可以与一个服务实例相关联
org.apache.catalina.core.StandardEngine类是Engine接口的标准实现,在实例化的时候,StandardEngine类会添加一个基础阀
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
}
org.apache.catalina.core.StandardEngineValve类是StandardEngine容器的基础阀,下面是它的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; // NOTE - Not much else we can do generically
} // Validate that any HTTP/1.1 request included a host header
HttpServletRequest hrequest = (HttpServletRequest) request;
if ("HTTP/1.1".equals(hrequest.getProtocol()) &&
(hrequest.getServerName() == null)) {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("standardEngine.noHostHeader",
request.getRequest().getServerName()));
return;
} // Select the Host to be used for this Request
StandardEngine engine = (StandardEngine) getContainer();
Host host = (Host) engine.map(request, true);
if (host == null) {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("standardEngine.noHost",
request.getRequest().getServerName()));
return;
} // Ask this Host to process this request
host.invoke(request, response); }
在验证了request和response对象的类型后,invoke()方法会通过调用Engine实例的map()方法获取Host对象;得到Host对象以后,调用其invoke()方法处理请求
---------------------------------------------------------------------------
本系列How Tomcat Works系本人原创
转载请注明出处 博客园 刺猬的温驯
本人邮箱: chenying998179#163.com (#改为@)
本文链接http://www.cnblogs.com/chenying99/p/3249152.html
How Tomcat Works(十六)的更多相关文章
- How Tomcat Works(六)
本文继续分析HttpProcessor类,该类实现了org.apache.catalina.Lifecycle接口和java.lang.Runnable接口 我们先分析它的构造函数 /** * The ...
- How Tomcat Works(十四)补充
在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...
- How Tomcat Works(十四)
我们已经知道,在tomcat中有四种类型的servlet容器,分别为Engine.Host.Context 和Wrapper,本文接下来对tomcat中Wrapper接口的标准实现进行说明. 对于每个 ...
- How Tomcat Works(二十)
要使用一个web应用程序,必须要将表示该应用程序的Context实例部署到一个host实例中.在tomcat中,context实例可以用war文件的形式来部署,也可以将整个web应用拷贝到Tomcat ...
- How Tomcat Works(十八)
在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...
- How Tomcat Works(十五)
本文接下来分析Context容器,Context容器实例表示一个具体的Web应用程序,其中包括一个或多个Wrapper实例:不过Context容器还需要其他的组件支持,典型的如载入器和Session管 ...
- How Tomcat Works(十二)
tomcat容器通过一个称为Session管理器的组件来管理建立的Session对象,该组件由org.apache.catalina.Manager接口表示:Session管理器必须与一个Contex ...
- How Tomcat Works(十)
本文接下来分析tomcat的日志记录器,日志记录器是用来记录消息的组件,在tomcat中,日志记录器需要与某个servlet容器相关连:在org.apache.catalina.logger包下,to ...
- How Tomcat Works(十九)
本文重点关注启动tomcat时会用到的两个类,分别为Catalina类和Bootstrap类,它们都位于org.apachae.catalina.startup包下:Catalina类用于启动或关闭S ...
随机推荐
- 工作流Activiti5流程变量 任务变量 setVariables 跟 setVariablesLocal区别
工作流Activiti5流程变量 任务变量 setVariables 和 setVariablesLocal区别 因为网上的资料比较少.结合源码把相关API写下来. 设置流程级别变量: runtime ...
- Spark 问题总结
1 创建hive外部表 其实这个问题应该是hive的问题.就是外部表在创建的时候需要指定目录.举例说明 我们要创建一个外部表,其来源是test_tab这个文件,那么在LOCATION处是不是这样写呢? ...
- Android 多进程编程 15问15答!
ps:阅读本文 需要对android 多进程编程有一定了解. 1.Android中总共有几种方式进行IPC? 答:一共有两种,一种是binder 还有一种是socket.Binder 大家用的比较多. ...
- 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.6. 安装Oracle所依赖的必要包
2.6. 安装Oracle所依赖的必要包 2.6.1. 检查Oracle所依赖的必要rpm包 [root@localhost /]#rpm -q binutils compat-libstdc elf ...
- MySQL基础之第17章 MySQL日志
17.1.日志简介 二进制日志错误日志通用查询日志慢查询日志 17.2.二进制日志 二进制日志也叫作变更日志(update log),主要用于记录数据库的变化情况.通过二进制日志可以查询MySQL数据 ...
- js细节
1.小心函数中的“s“ getElementsByTagName:得到的是数组 getElementById:得到的是对象 2.js 中设置哪一项被选中 subject.selectedIndex = ...
- jQuery Mobile中文手册:开发入门
jQuery Mobile 以“Write Less, Do More”作为目标,为所有的主流移动操作系统平台提供了高度统一的 UI 框架:jQuery 的移动框架可以让你为所有流行的移动平台设计一个 ...
- Android服务之Service
android中服务是运行在后台的东西,级别与activity差不多.既然说service是运行在后台的服务,那么它就是不可见的,没有界面的东西.你可以启动一个服务Service来播放音乐,或者记录你 ...
- 【leetcode】Find Minimum in Rotated Sorted Array II JAVA实现
一.题目描述 Follow up for "Find Minimum in Rotated Sorted Array":What if duplicates are allowed ...
- HTTP协议学习笔记-1
基本概念 首先需要了解几个概念: WEB客户端和服务器: WEB客户端当然就是指我们用使用的某个网站 服务器就是WEB资源源头,我们从服务器去请求数据,服务器把请求的数据发给WEB客户端 媒体类型: ...