- 浏览: 827029 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
renzhengzhi:
请教一下楼主,公有云和私有云的开发,具体要做哪些工作呢?我拿到 ...
4,云的4 种模式 -
SangBillLee:
我用了solr5.5,用SolrQuery查询,没法高亮,不知 ...
solr5.x快速入门 -
lw900925:
这翻译读起来真是别扭。
solr in action翻译-第一章1.1 -
springjpa_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
Spring MVC性能提升 -
h416373073:
正遇到了此问题不知如何解决, 多谢分享
solr错误
Wrapper接口在Catalina中的标准实现StandardWrapper类的详细实现过程。
一共有四种容器:engine(引擎),host(主机),context(上下文)和wrapper(包装器)
一个上下文一般包括一个或者多个包装器,每一个包装器表示一个servlet
方法调用序列Sequence of Methods Invocation
对于每一个连接,连接器都会调用关联容器的invoke方法。接下来容器调用它的所有子容器的invoke方法
如果一个连接器跟一个StadardContext实例相关联,那么连接器会调用StandardContext实例的invoke方法,
该方法会调用所有它的子容器的invoke方法
过程
1,连接器创建请求和响应对象
2,连接器调用StandardContext的invoke方法
3,StandardContext的invoke方法必须调用该上下文容器的流水线的invoke方法,
所以StandardContext的流水线会调用StandardContextValve的invoke方法
4,StandardContextValve的invoke方法得到合适的包装器来对请求进行服务并调用包装器的invoke方法
5,StandardWrapper是包装器的标准实现,StandardWrapper对象的invoke方法调用流水线的invoke方法。
6,StandardWrapper流水线的基本阀门时StandardWrapperValve。因此StandardWrapperValve的invoke方法会被调用。
StandardWrapperValve的invoke方法会调用包装器的allocate方法获得一个servlet的实例。
7,当一个servlet需要被加载的时候,方法allocate调用方法load来加载一个servlet
8,方法load会调用servlet的init方法
我们主要关注的是一个servlet被调用的时候发生的细节。因此我们需要自习看StandardWrapper和StandarWrapperValve类
javax.servlet.SingleThreadModel
一个servlet可以实现javax.servlet.SingleThreadModel接口,实现此接口的一个servlet通俗称为SingleThreadModel(STM)的程序组件。
根据Servlet规范,实现此接口的目的是保证servlet一次只能有一个请求。
StandardWrapper
一个StandardWrapper对象的主要职责是:加载它表示的servlet并分配它的一个实例。该StandardWrapper不会调用servlet的service方法
这个任务留给StandardWrapperValve对象,在StandardWrapper实例的基本阀门管道。
StandardWrapperValve对象通过调用StandardWrapper的allocate方法获得Servlet实例。
在获得Servlet实例之后的StandardWrapperValve调用servlet的service方法
在servlet第一次被请求的时候,StandardWrapper加载servlet类。它是动态的加载servlet,所以需要知道servlet类的完全限定名称。
通过StandardWrapper类的setServletClass方法将servlet的类名传递给StandardWrapper。
必须考虑一个servlet是否实现了SingleThreadModel接口。 如果一个servlet没有实现SingleThreadModel接口,
StandardWrapper加载该servlet一次,对于以后的请求返回相同的实例即可。
对于一个STM servlet,情况就有所不同了。StandardWrapper必须保证不能同时有两个线程提交STM servlet的service方法。
Servlet instance = <get an instance of the servlet>; if ((servlet implementing SingleThreadModel>) { synchronized (instance) { instance.service(request, response); } }else{ instance.service(request, response); }
Allocating the Servlet
StandardWrapperValve的invoke方法调用了包装器的allocate方法来获得一个请求servlet的实例
因此StandardWrapper类必须实现该接口
public javax.servlet.Servlet allocate() throws ServletException;
由于要支持STM servlet,这使得该方法更复杂了一点。实际上,该方法有两部分组成,
一部分负责非STM servlet的工作,另一部分负责STM servlet。
第一部分的结构如下
if (!singleThreadModel) {
// returns a non-STM servlet instance
}
布尔变量singleThreadModel负责标志一个servlet是否是STM servlet。
它的初始值是false,loadServlet方法会检测加载的servlet是否是STM的,如果是则将它的值该为true
第二部分处理singleThreadModel为true的情况
synchronized (instancepool) {
// returns an instance of the servlet from the pool
}
对于非STM servlet,StandardWrapper定义一个java.servlet.Servlet类型的实例
private Servlet instance = null;
方法allocate检查该实例是否为null,如果是调用loadServlet方法来加载servlet。然后增加contAllocated整型并返回该实例。
if (!singleThreadModel) { if (instance == null) { synchronized (this) { if (instance == null) { try { instance = loadServlet(); }catch (ServletException e) { throw e; } } } } if (!singleThreadModel) { countAllocated++; return (instance); }
Loading the Servlet
StandardWrapper实现了Wrapper接口的load方法,load方法调用loadServlet方法来加载一个servlet类,
并调用该servlet的init方法,传递一个javax.servlet.ServletConfig实例
方法loadServlet首先检查StandardWrapper是否表示一个STM servlet。
如果不是并且该实例不是null(即以前已经加载过),直接返回该实例:
if (!singleThreadModel && (instance != null))
return instance;
如果该实例是null或者是一个STM servlet,继续该方法的其它部分
ServletConfig对象
StandardWrapper的loadServlet方法在加载了loaded方法之后调用的发送者的init方法
init方法传递一个javax.servlet.ServletConfig实例
StandardWrapper实现javax.servlet.ServletConfig接口和Wrapper接口。
ServletConfig接口有以下四个方法getServletContext, getServletName, getInitParameter, 和getInitParameterNames
getServletContext
public ServletContext getServletContext()
一个StandardWrapper实例必须是一个StandardContext容器的子容器。也就是说,StandardWrapper的父容器是StandardContext
StandardWrapper中方法getServletContext的实现
public ServletContext getServletContext() { if (parent == null) return (null); else if (!(parent instanceof Context)) return (null); else return (((Context) parent).getServletContext()); }
现在你知道不能单独部署一个包装器来表示一个Servlet,包装器必须从属于一个上下文容器,
这样才能使用ServletConfig对象使用getServletContext方法获得一个ServletContext实例。
getServletName
该方法返回Servlet的名字
public java.lang.String getServletName()
getServletName方法在StandardWrapper类中实现
public String getServletName() {
return (getName());
}
它简单的调用StandardWrapper 的父类ContainerBase类的getName方法
在ContainerBase中如下实现
public String getName() {
return (name);
}
使用setName方法来设置name的值。回忆是如何调用StandardWrapper实例的setName方法来传递Servlet的name的
getInitParameter
该方法返回指定参数的值
public java.lang.String getInitParameter(java.lang.String name)
在StandardWrapper中,初始化参数被存放在一个名为parameters的HashMap中
private HashMap parameters = new HashMap(); StandardWrapper类的addInitParameter方法来填充parameters。传递参数的名字和值。 public void addInitParameter(String name, String value) { synchronized (parameters) { parameters.put(name, value); } fireContainerEvent("addInitParameter", name); } StandardWrapper对getInitParameter的实现: public String getInitParameter(String name) { return (findInitParameter(name)); }
getInitParameterNames
该方法返回所有初始化参数名字的枚举(Enumeration),
public java.util.Enumeration getInitParameterNames()
StandardWrapper类中getInitParameterNames的实现:
public Enumeration getInitParameterNames() {
synchronized (parameters) {
return (new Enumerator(parameters.keyset()));
}
}
Parent and Children
一个包装器表示一个独立Servlet的容器。这样,包装器就不能再有子容器,因此不可以调用它的addChild方法,
如果调用了会得到一个java.langIllegalStateException
一个包装器的父容器只能是一个上下文容器。如果传递的参数不是一个上下文容器,
它的setParent方法会抛出java.lang.IllegalArgumentException
public void setParent(Container container) { if ((container != null) && !(container instanceof Context)) throw new IllegalArgumentException ( sm.getString("standardWrapper.notContext")); super.setParent(container); }
StandardWrapperFacade
StandardWrapper调用它价值的Servlet的init方法。该方法需要一个javax.servlet.ServletConfig的参数,
而StandardWrapper类自己就实现了ServletConfig接口。所以,理论上StandardWrapper可以将它自己作为参数传递给init方法。
但是StandardWrapper需要对Servlet隐藏他的大多数public方法。
为了实现这一点,StandardWraper将它自己包装的一个StandardWrapperFacade实例中
StandardWrapperValve
StandardWrapperValve是StandardWrapper实例上的基本阀门,主要工作是
1,提交Servlet的所有相关过滤器
2,调用发送者的service方法
要实现这些内容,下面是StandardWrapperValve在他的invoke方法要实现的
· 调用StandardWrapper的allocate的方法来获得一个servlet实例
· 调用它的private createFilterChain方法获得过滤链
· 调用过滤器链的doFilter方法。包括调用servlet的service方法
· 释放过滤器链
· 调用包装器的deallocate方法
· 如果Servlet无法使用了,调用包装器的unload方法
接下来是invoke方法
try { if (!unavailable) { servlet = wrapper.allocate(); } } ......... try { response.sendAcknowledgement(); } ........ ApplicationFilterChain filterChain = createFilterChain(request, servlet); try { String jspFile = wrapper.getJspFile(); if (jspFile != null) sreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile); else sreq.removeAttribute(Globals.JSP_FILE_ATTR); if ((servlet != null) && (filterChain != null)) { filterChain.doFilter(sreq, sres); } sreq.removeAttribute(Globals.JSP_FILE_ATTR); .... } ........... try { if (filterChain != null) filterChain.release(); } ... try { if (servlet != null) { wrapper.deallocate(servlet); } } ........ try { if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) { wrapper.unload(); } }
最重要的方法是createFilterChain方法并调用过滤器链的doFilter方法。
方法createFilterChain创建了一个ApplicationFilterChain实例,并将所有的过滤器添加到上面
FilterDef
org.apache.catalina.deploy.FilterDef表示一个过滤器定义,就像是在部署文件中定义一个过滤器元素那样
public final class FilterDef { /** * The description of this filter. */ private String description = null; private String displayName = null; private String filterClass = null; private String filterName = null; private String largeIcon = null; private String smallIcon = null; private Map parameters = new HashMap(); public String toString() { StringBuffer sb = new StringBuffer("FilterDef["); sb.append("filterName="); sb.append(this.filterName); sb.append(", filterClass="); sb.append(this.filterClass); sb.append("]"); return (sb.toString()); } public void addInitParameter(String name, String value) { parameters.put(name, value); } }
FilterDef类中的每一个属性都代表一个可以在过滤器中出现的子元素。该类包括一个Map类型的变量表示一个包含所有初始参数的Map。
方法addInitParameer添加一个name/value对到该Map。
ApplicationFilterConfig
ApplicationFilterConfig实现了javax.servlet.FilterConfig接口。
ApplicationFilterConfig负责管理web应用程序启动的时候创建的过滤器实例。
传递一个org.apache.catalina.Context对象和FilterDef对象给ApplicationFilterConfig的构造来创建一个ApplicationFilterConfig实例:
public ApplicationFilterConfig(Context context, FilterDef filterDef)
throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException
Context对象表示一个一个web应用而FilterDef表示一个过滤器定义。
Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException { if (this.filter != null) return (this.filter); String filterClass = filterDef.getFilterClass(); ClassLoader classLoader = null; if (filterClass.startsWith("org.apache.catalina.")) classLoader = this.getClass().getClassLoader(); else classLoader = context.getLoader().getClassLoader(); ClassLoader oldCtxClassLoader = Thread.currentthread().getContextClassLoader(); Class clazz = classLoader.loadClass(filterClass); this.filter = (Filter) clazz.newInstance(); filter.init(this); return (this.filter); }
ApplicationFilterChain
ApplicationFilterChain类是实现了javax.servlet.FilterChain接口。
StandardWrapperValve类中的invoke方法创建一个该类的实例并且调用它的doFilter方法。
ApplicationFilterChain类的doFilter的调用该链中第一个过滤器的doFilter方法。
Filter接口中doFilter方法的签名如下:
public void doFilter(ServletRaquest request, ServletResponse response, FilterChain chain)
在他的doFilter方法中,一个过滤器可以调用另一个过滤器链的doFilter来唤醒另一个过来出去
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // do something here ... chain.doFilter(request, response); }
在doFilter方法最好一行,它调用过滤链的doFilter方法。如果该过滤器是过滤链的最后一个过滤器,
它叫调用请求的Servlet的service方法。如果过滤器没有调用chain.doFilter,下一个过滤器就不会被调用。
发表评论
-
21,tomcat关闭钩子
2012-11-22 20:35 6594在很多环境下,在关闭应用程序的时候需要做一些清理工作。问题在于 ... -
20,tomcat的XML解析---digester
2012-11-22 20:07 1518tomcat使用server.xml配置属性信息Tomcat使 ... -
19tomcat的服务器和服务
2012-11-20 20:10 1045Server服务器 Server接口表示整个Catalina ... -
18,tomcat的主机(host)和引擎
2012-11-16 09:13 2316如果需要在一个Tomcat部署中部署多个上下文,需要使用一个主 ... -
附,listener、 filter、servlet 加载顺序及其详解
2012-11-15 09:10 963一、 1、启动一个WEB项 ... -
17,tomcat中StandardContext
2012-11-15 08:59 4999一个上下文容器(Context)代表一个web应用,每一个上下 ... -
15,tomcat安全
2012-11-14 09:02 1172有些web应用程序的内容是有限制的,只允许有权限的用户在提供正 ... -
14,tomcat session管理
2012-11-14 09:01 1073Catalina通过一个叫管理器的组建来完成Session的管 ... -
13.tomcat加载器
2012-11-13 13:21 1355库(repository)和源(res ... -
12,tomcat日志处理
2012-11-13 13:15 1223日志系统是一个记录信息的组件。在Catalina中,日志系统是 ... -
附:JAVA事件处理--观察者模式
2012-11-12 10:33 958简单地说,观察者模式 ... -
11.tomcat生命周期
2012-11-12 10:26 971Catalina由多个组件组成,当Catalina启动的 ... -
10.容器
2012-11-12 10:12 1327容器是一个处理用户servlet请求并返回对象给we ... -
9.Tomcat的默认连接器
2012-11-12 08:52 1147Tomcat连接器是一个可以插入servlet容器的独立模块, ... -
8.连接器
2012-11-12 08:46 902一个可以创建更好的请 ... -
7,Facade外观模式
2012-11-08 11:28 924外观模式:为子系统中的一组接口提供了一个一致的界面,此模式定义 ... -
6,一个简单的servlet容器
2012-11-08 11:10 825总的来说,一个全功能的servlet容器会为servlet的每 ... -
5.javax.servlet.Servlet接口
2012-11-08 09:18 922javax.servlet.Servlet接口Servlet编 ... -
4,一个简单的tomcat
2012-11-07 18:10 873流程图如下 -
3.ServerSocket 与 Socket的区别
2012-11-07 16:56 11001.1 ServerSocket类创建 ...
相关推荐
《深入剖析Tomcat》从最基本的HTTP请求开始,直至使用JMX技术管理Tomcat中的应用程序,逐一剖析Tomcat的基本功能模块,并配以示例代码,使读者可以逐步实现自己的Web服务器。 目录 第1章 一个简单的web服务器 1.1...
主要介绍了Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解,需要的朋友可以参考下
外观设计模式在Tomcat中有多处使用,在Request和Response对象封装中、StandardWrapper到ServletConfig封装中、ApplicationContext到ServletContext封装中等都用到了这种设计模式。这么多场合都用到了这种设计模式,...
NULL 博文链接:https://sulin.iteye.com/blog/1040747
第十一章StandardWrapper 第十二章StandardContext 第十三章主机和引擎 第十四章服务器组件和服务组件 第十五章消化器库 第十六章关闭钩子 第十七章启动Tomcat 第十八章部署器 第十九章Manager应用程序的servlet类 ...
16.2 tomcat中的shutdown hook 131 第17章 启动tomcat 133 17.1 概述 133 17.2 Catalina类 133 17.2.1 start方法 134 17.2.2 stop方法 135 17.2.3 启动Digester 135 17.2.4 关闭Digester 135 17.3 Bootstrap类 136 ...
讲述Tomcat的工作原理 第1章 一个简单的Web服务器 第2章 一个简单的servlet容器 第3章 连接器(Connector) 第4章 tomcat的默认连接器 第5章 container ...第11章 StandardWrapper 第12章 StandardContext类 ...
16.2 tomcat中的shutdown hook 131 第17章 启动tomcat 133 17.1 概述 133 17.2 Catalina类 133 17.2.1 start方法 134 17.2.2 stop方法 135 17.2.3 启动Digester 135 17.2.4 关闭Digester 135 17.3 Bootstrap类 136 ...
门面设计模式门面设计模式在Tomcat中有多处使用,在Request和Response对象封装中、StandardWrapper到ServletConfig封装中、ApplicationContext到ServletContext封装中等都用到了这种设计模式。门面设计模式的原理...
(基础夯实一点,会有好处的,排错的时候就体现出来了) 下面就Ext.Direct做一些排错笔记: 错误一: 代码如下: 严重: StandardWrapper.Throwable java.lang.ArrayIndexOutOfBoundsException: 1 at ...