Servlet底层原理(18页).doc
《Servlet底层原理(18页).doc》由会员分享,可在线阅读,更多相关《Servlet底层原理(18页).doc(18页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、-Servlet底层原理-第 18 页Servlet底层原理从 Servlet 容器说起要介绍 Servlet 必须要先把 Servlet 容器说清楚,Servlet 与 Servlet 容器的关系有点像枪和子弹的关系,枪是为子弹而生,而子弹又让枪有了杀伤力。虽然它们是彼此依存的,但是又相互独立发展,这一切都是为了适应工业化生产的结果。从技术角度来说是为了解耦,通过标准化接口来相互协作。既然接口是连接 Servlet 与 Servlet 容器的关键,那我们就从它们的接口说起。前面说了 Servlet 容器作为一个独立发展的标准化产品,目前它的种类很多,但是它们都有自己的市场定位,很难说谁优谁劣
2、,各有特点。例如现在比较流行的 Jetty,在定制化和移动领域有不错的发展,我们这里还是以大家最为熟悉 Tomcat 为例来介绍 Servlet 容器如何管理 Servlet。Tomcat 本身也很复杂,我们只从 Servlet 与 Servlet 容器的接口部分开始介绍,关于 Tomcat 的详细介绍可以参考我的另外一篇文章 Tomcat 系统架构与模式设计分析。Tomcat 的容器等级中,Context 容器是直接管理 Servlet 在容器中的包装类 Wrapper,所以 Context 容器如何运行将直接影响 Servlet 的工作方式。图 1 . Tomcat 容器模型从上图可以看出
3、 Tomcat 的容器分为四个等级,真正管理 Servlet 的容器是 Context 容器,一个 Context 对应一个 Web 工程,在 Tomcat 的配置文件中可以很容易发现这一点,如下:清单 1 Context 配置参数 下面详细介绍一下 Tomcat 解析 Context 容器的过程,包括如何构建 Servlet 的过程。Servlet 容器的启动过程清单 2 . 给 Tomcat 增加一个 Web 工程 Tomcat tomcat = getTomcatInstance(); File appDir = new File(getBuildDirectory(), webapps
4、/examples); tomcat.addWebapp(null, /examples, appDir.getAbsolutePath(); tomcat.start(); ByteChunk res = getUrl(http:/localhost: + getPort() + /examples/servlets/servlet/HelloWorldExample); assertTrue(res.toString().indexOf(Hello World!) 0); 清单 1 的代码是创建一个 Tomcat 实例并新增一个 Web 应用,然后启动 Tomcat 并调用其中的一个 He
5、lloWorldExample Servlet,看有没有正确返回预期的数据。Tomcat 的 addWebapp 方法的代码如下:清单 3 .Tomcat.addWebapp public Context addWebapp(Host host, String url, String path) silence(url); Context ctx = new StandardContext(); ctx.setPath( url ); ctx.setDocBase(path); if (defaultRealm = null) initSimpleAuth(); ctx.setRealm(de
6、faultRealm); ctx.addLifecycleListener(new DefaultWebXmlListener(); ContextConfig ctxCfg = new ContextConfig(); ctx.addLifecycleListener(ctxCfg); ctxCfg.setDefaultWebXml(org/apache/catalin/startup/NO_DEFAULT_XML); if (host = null) getHost().addChild(ctx); else host.addChild(ctx); return ctx; 前面已经介绍了一
7、个 Web 应用对应一个 Context 容器,也就是 Servlet 运行时的 Servlet 容器,添加一个 Web 应用时将会创建一个 StandardContext 容器,并且给这个 Context 容器设置必要的参数,url 和 path 分别代表这个应用在 Tomcat 中的访问路径和这个应用实际的物理路径,这个两个参数与清单 1 中的两个参数是一致的。其中最重要的一个配置是 ContextConfig,这个类将会负责整个 Web 应用配置的解析工作,后面将会详细介绍。最后将这个 Context 容器加到父容器 Host 中。接下去将会调用 Tomcat 的 start 方法启动
8、Tomcat,如果你清楚 Tomcat 的系统架构,你会容易理解 Tomcat 的启动逻辑,Tomcat 的启动逻辑是基于观察者模式设计的,所有的容器都会继承 Lifecycle 接口,它管理者容器的整个生命周期,所有容器的的修改和状态的改变都会由它去通知已经注册的观察者(Listener),关于这个设计模式可以参考 Tomcat 的系统架构与设计模式,第二部分:设计模式。Tomcat 启动的时序图可以用图 2 表示。图 2. Tomcat 主要类的启动时序图(查看大图)上图描述了 Tomcat 启动过程中,主要类之间的时序关系,下面我们将会重点关注添加 examples 应用所对应的 Sta
9、ndardContext 容器的启动过程。当 Context 容器初始化状态设为 init 时,添加在 Contex 容器的 Listener 将会被调用。ContextConfig 继承了 LifecycleListener 接口,它是在调用清单 3 时被加入到 StandardContext 容器中。ContextConfig 类会负责整个 Web 应用的配置文件的解析工作。ContextConfig 的 init 方法将会主要完成以下工作:1. 创建用于解析 xml 配置文件的 contextDigester 对象 2. 读取默认 context.xml 配置文件,如果存在解析它 3.
10、读取默认 Host 配置文件,如果存在解析它 4. 读取默认 Context 自身的配置文件,如果存在解析它 5. 设置 Context 的 DocBase ContextConfig 的 init 方法完成后,Context 容器的会执行 startInternal 方法,这个方法启动逻辑比较复杂,主要包括如下几个部分:1. 创建读取资源文件的对象 2. 创建 ClassLoader 对象 3. 设置应用的工作目录 4. 启动相关的辅助类如:logger、realm、resources 等 5. 修改启动状态,通知感兴趣的观察者(Web 应用的配置) 6. 子容器的初始化 7. 获取 Ser
11、vletContext 并设置必要的参数 8. 初始化“load on startup”的 Servlet Web 应用的初始化工作Web 应用的初始化工作是在 ContextConfig 的 configureStart 方法中实现的,应用的初始化主要是要解析 web.xml 文件,这个文件描述了一个 Web 应用的关键信息,也是一个 Web 应用的入口。接下去将会将 WebXml 对象中的属性设置到 Context 容器中,这里包括创建 Servlet 对象、filter、listener 等等。这段代码在 WebXml 的 configureContext 方法中。下面是解析 Servl
12、et 的代码片段:清单 4. 创建 Wrapper 实例 for (ServletDef servlet : servlets.values() Wrapper wrapper = context.createWrapper(); String jspFile = servlet.getJspFile(); if (jspFile != null) wrapper.setJspFile(jspFile); if (servlet.getLoadOnStartup() != null) wrapper.setLoadOnStartup(servlet.getLoadOnStartup().int
13、Value(); if (servlet.getEnabled() != null) wrapper.setEnabled(servlet.getEnabled().booleanValue(); wrapper.setName(servlet.getServletName(); Map params = servlet.getParameterMap(); for (Entry entry : params.entrySet() wrapper.addInitParameter(entry.getKey(), entry.getValue(); wrapper.setRunAs(servle
14、t.getRunAs(); Set roleRefs = servlet.getSecurityRoleRefs(); for (SecurityRoleRef roleRef : roleRefs) wrapper.addSecurityReference( roleRef.getName(), roleRef.getLink(); wrapper.setServletClass(servlet.getServletClass(); MultipartDef multipartdef = servlet.getMultipartDef(); if (multipartdef != null)
15、 if (multipartdef.getMaxFileSize() != null & multipartdef.getMaxRequestSize()!= null & multipartdef.getFileSizeThreshold() != null) wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation(), Long.parseLong(multipartdef.getMaxFileSize(), Long.parseLong(multipartdef.getM
16、axRequestSize(), Integer.parseInt( multipartdef.getFileSizeThreshold(); else wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation(); if (servlet.getAsyncSupported() != null) wrapper.setAsyncSupported( servlet.getAsyncSupported().booleanValue(); context.addChild(wrap
17、per); 这段代码清楚的描述了如何将 Servlet 包装成 Context 容器中的 StandardWrapper,这里有个疑问,为什么要将 Servlet 包装成 StandardWrapper 而不直接是 Servlet 对象。这里 StandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特征,而 Servlet 为了一个独立的 web 开发标准,不应该强耦合在 Tomcat 中。除了将 Servlet 包装成 StandardWrapper 并作为子容器添加到 Context 中,其它的所有 web.xml 属性都被解析到 Context 中,所以说 Cont
18、ext 容器才是真正运行 Servlet 的 Servlet 容器。一个 Web 应用对应一个 Context 容器,容器的配置属性由应用的 web.xml 指定,这样我们就能理解 web.xml 到底起到什么作用了。创建 Servlet 实例前面已经完成了 Servlet 的解析工作,并且被包装成 StandardWrapper 添加在 Context 容器中,但是它仍然不能为我们工作,它还没有被实例化。下面我们将介绍 Servlet 对象是如何创建的,以及如何被初始化的。创建 Servlet 对象创建 Servlet 对象的相关类结构图如下:图 3. 创建 Servlet 对象的相关类结构
19、初始化 Servlet初始化 Servlet 在 StandardWrapper 的 initServlet 方法中,这个方法很简单就是调用 Servlet 的 init 的方法,同时把包装了 StandardWrapper 对象的 StandardWrapperFacade 作为 ServletConfig 传给 Servlet。Tomcat 容器为何要传 StandardWrapperFacade 给 Servlet 对象将在后面做详细解析。如果该 Servlet 关联的是一个 jsp 文件,那么前面初始化的就是 JspServlet,接下去会模拟一次简单请求,请求调用这个 jsp 文件,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Servlet 底层 原理 18
限制150内