ImageVerifierCode 换一换
格式:DOCX , 页数:17 ,大小:274.49KB ,
资源ID:5750641      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5750641.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Servlet 工作原理解析.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Servlet 工作原理解析.docx

1、Servlet 工作原理解析Servlet 工作原理解析Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础。因而掌握 Servlet 的工作原理是成为一名合格的 Java Web 技术开发人员的基本要求。本文将带你认识 Java Web 技术是如何基于 Servlet 工作,你将知道:以 Tomcat 为例了解 Servlet 容器是如何工作的?一个 Web 工程在 Servlet 容器中是如何启动的? Servlet 容器如何解析你在 web.xml 中定义的 Servlet ?用户的请求是如何被分配给指定的 Servlet 的?

2、 Servlet 容器如何管理 Servlet 生命周期?你还将了解到最新的 Servlet 的 API 的类层次结构,以及 Servlet 中一些难点问题的分析。从 Servlet 容器说起要介绍 Servlet 必须要先把 Servlet 容器说清楚,Servlet 与 Servlet 容器的关系有点像枪和子弹的关系,枪是为子弹而生,而子弹又让枪有了杀伤力。虽然它们是彼此依存的,但是又相互独立发展,这一切都是为了适应工业化生产的结果。从技术角度来说是为了解耦,通过标准化接口来相互协作。既然接口是连接 Servlet 与 Servlet 容器的关键,那我们就从它们的接口说起。前面说了 Ser

3、vlet 容器作为一个独立发展的标准化产品,目前它的种类很多,但是它们都有自己的市场定位,很难说谁优谁劣,各有特点。例如现在比较流行的 Jetty,在定制化和移动领域有不错的发展,我们这里还是以大家最为熟悉 Tomcat 为例来介绍 Servlet 容器如何管理 Servlet。Tomcat 本身也很复杂,我们只从 Servlet 与 Servlet 容器的接口部分开始介绍,关于 Tomcat 的详细介绍可以参考我的另外一篇文章 Tomcat 系统架构与模式设计分析。Tomcat 的容器等级中,Context 容器是直接管理 Servlet 在容器中的包装类 Wrapper,所以 Contex

4、t 容器如何运行将直接影响 Servlet 的工作方式。图 1 . Tomcat 容器模型从上图可以看出 Tomcat 的容器分为四个等级,真正管理 Servlet 的容器是 Context 容器,一个 Context 对应一个 Web 工程,在 Tomcat 的配置文件中可以很容易发现这一点,如下:清单 1 Context 配置参数 下面详细介绍一下 Tomcat 解析 Context 容器的过程,包括如何构建 Servlet 的过程。Servlet 容器的启动过程Tomcat7 也开始支持嵌入式功能,增加了一个启动类 org.apache.catalina.startup.Tomcat。创

5、建一个实例对象并调用 start 方法就可以很容易启动 Tomcat,我们还可以通过这个对象来增加和修改 Tomcat 的配置参数,如可以动态增加 Context、Servlet 等。下面我们就利用这个 Tomcat 类来管理新增的一个 Context 容器,我们就选择 Tomcat7 自带的 examples Web 工程,并看看它是如何加到这个 Context 容器中的。清单 2 . 给 Tomcat 增加一个 Web 工程 Tomcat tomcat = getTomcatInstance(); File appDir = new File(getBuildDirectory(), we

6、bapps/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 并调用其中的一

7、个 HelloWorldExample 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.setReal

8、m(defaultRealm); 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; 前面已经

9、介绍了一个 Web 应用对应一个 Context 容器,也就是 Servlet 运行时的 Servlet 容器,添加一个 Web 应用时将会创建一个 StandardContext 容器,并且给这个 Context 容器设置必要的参数,url 和 path 分别代表这个应用在 Tomcat 中的访问路径和这个应用实际的物理路径,这个两个参数与清单 1 中的两个参数是一致的。其中最重要的一个配置是 ContextConfig,这个类将会负责整个 Web 应用配置的解析工作,后面将会详细介绍。最后将这个 Context 容器加到父容器 Host 中。接下去将会调用 Tomcat 的 start 方

10、法启动 Tomcat,如果你清楚 Tomcat 的系统架构,你会容易理解 Tomcat 的启动逻辑,Tomcat 的启动逻辑是基于观察者模式设计的,所有的容器都会继承 Lifecycle 接口,它管理者容器的整个生命周期,所有容器的的修改和状态的改变都会由它去通知已经注册的观察者(Listener),关于这个设计模式可以参考 Tomcat 的系统架构与设计模式,第二部分:设计模式。Tomcat 启动的时序图可以用图 2 表示。图 2. Tomcat 主要类的启动时序图(查看大图)上图描述了 Tomcat 启动过程中,主要类之间的时序关系,下面我们将会重点关注添加 examples 应用所对应的

11、 StandardContext 容器的启动过程。当 Context 容器初始化状态设为 init 时,添加在 Contex 容器的 Listener 将会被调用。ContextConfig 继承了 LifecycleListener 接口,它是在调用清单 3 时被加入到 StandardContext 容器中。ContextConfig 类会负责整个 Web 应用的配置文件的解析工作。ContextConfig 的 init 方法将会主要完成以下工作:创建用于解析 xml 配置文件的 contextDigester 对象读取默认 context.xml 配置文件,如果存在解析它读取默认 Ho

12、st 配置文件,如果存在解析它读取默认 Context 自身的配置文件,如果存在解析它设置 Context 的 DocBaseContextConfig 的 init 方法完成后,Context 容器的会执行 startInternal 方法,这个方法启动逻辑比较复杂,主要包括如下几个部分:创建读取资源文件的对象创建 ClassLoader 对象设置应用的工作目录启动相关的辅助类如:logger、realm、resources 等修改启动状态,通知感兴趣的观察者(Web 应用的配置)子容器的初始化获取 ServletContext 并设置必要的参数初始化“load on startup”的 S

13、ervletWeb 应用的初始化工作Web 应用的初始化工作是在 ContextConfig 的 configureStart 方法中实现的,应用的初始化主要是要解析 web.xml 文件,这个文件描述了一个 Web 应用的关键信息,也是一个 Web 应用的入口。Tomcat 首先会找 globalWebXml 这个文件的搜索路径是在 engine 的工作目录下寻找以下两个文件中的任一个 org/apache/catalin/startup/NO_DEFAULT_XML 或 conf/web.xml。接着会找 hostWebXml 这个文件可能会在 System.getProperty(cat

14、alina.base)/conf/$EngineName/$HostName/web.xml.default,接着寻找应用的配置文件 examples/WEB-INF/web.xml。web.xml 文件中的各个配置项将会被解析成相应的属性保存在 WebXml 对象中。如果当前应用支持 Servlet3.0,解析还将完成额外 9 项工作,这个额外的 9 项工作主要是为 Servlet3.0 新增的特性,包括 jar 包中的 META-INF/web-fragment.xml 的解析以及对 annotations 的支持。接下去将会将 WebXml 对象中的属性设置到 Context 容器中,这

15、里包括创建 Servlet 对象、filter、listener 等等。这段代码在 WebXml 的 configureContext 方法中。下面是解析 Servlet 的代码片段:清单 4. 创建 Wrapper 实例 for (ServletDef servlet : servlets.values() Wrapper wrapper = context.createWrapper(); String jspFile = servlet.getJspFile(); if (jspFile != null) wrapper.setJspFile(jspFile); if (servlet.

16、getLoadOnStartup() != null) wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue(); if (servlet.getEnabled() != null) wrapper.setEnabled(servlet.getEnabled().booleanValue(); wrapper.setName(servlet.getServletName(); Map params = servlet.getParameterMap(); for (Entry entry : params.entrySet()

17、 wrapper.addInitParameter(entry.getKey(), entry.getValue(); wrapper.setRunAs(servlet.getRunAs(); Set roleRefs = servlet.getSecurityRoleRefs(); for (SecurityRoleRef roleRef : roleRefs) wrapper.addSecurityReference( roleRef.getName(), roleRef.getLink(); wrapper.setServletClass(servlet.getServletClass(

18、); MultipartDef multipartdef = servlet.getMultipartDef(); if (multipartdef != null) if (multipartdef.getMaxFileSize() != null & multipartdef.getMaxRequestSize()!= null & multipartdef.getFileSizeThreshold() != null) wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocatio

19、n(), Long.parseLong(multipartdef.getMaxFileSize(), Long.parseLong(multipartdef.getMaxRequestSize(), Integer.parseInt( multipartdef.getFileSizeThreshold(); else wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation(); if (servlet.getAsyncSupported() != null) wrapper.s

20、etAsyncSupported( servlet.getAsyncSupported().booleanValue(); context.addChild(wrapper); 这段代码清楚的描述了如何将 Servlet 包装成 Context 容器中的 StandardWrapper,这里有个疑问,为什么要将 Servlet 包装成 StandardWrapper 而不直接是 Servlet 对象。这里 StandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特征,而 Servlet 为了一个独立的 web 开发标准,不应该强耦合在 Tomcat 中。除了将 Servl

21、et 包装成 StandardWrapper 并作为子容器添加到 Context 中,其它的所有 web.xml 属性都被解析到 Context 中,所以说 Context 容器才是真正运行 Servlet 的 Servlet 容器。一个 Web 应用对应一个 Context 容器,容器的配置属性由应用的 web.xml 指定,这样我们就能理解 web.xml 到底起到什么作用了。回页首创建 Servlet 实例前面已经完成了 Servlet 的解析工作,并且被包装成 StandardWrapper 添加在 Context 容器中,但是它仍然不能为我们工作,它还没有被实例化。下面我们将介绍 S

22、ervlet 对象是如何创建的,以及如何被初始化的。创建 Servlet 对象如果 Servlet 的 load-on-startup 配置项大于 0,那么在 Context 容器启动的时候就会被实例化,前面提到在解析配置文件时会读取默认的 globalWebXml,在 conf 下的 web.xml 文件中定义了一些默认的配置项,其定义了两个 Servlet,分别是:org.apache.catalina.servlets.DefaultServlet 和 org.apache.jasper.servlet.JspServlet 它们的 load-on-startup 分别是 1 和 3,也

23、就是当 Tomcat 启动时这两个 Servlet 就会被启动。创建 Servlet 实例的方法是从 Wrapper. loadServlet 开始的。loadServlet 方法要完成的就是获取 servletClass 然后把它交给 InstanceManager 去创建一个基于 servletClass.class 的对象。如果这个 Servlet 配置了 jsp-file,那么这个 servletClass 就是 conf/web.xml 中定义的 org.apache.jasper.servlet.JspServlet 了。创建 Servlet 对象的相关类结构图如下:图 3. 创建

24、 Servlet 对象的相关类结构初始化 Servlet初始化 Servlet 在 StandardWrapper 的 initServlet 方法中,这个方法很简单就是调用 Servlet 的 init 的方法,同时把包装了 StandardWrapper 对象的 StandardWrapperFacade 作为 ServletConfig 传给 Servlet。Tomcat 容器为何要传 StandardWrapperFacade 给 Servlet 对象将在后面做详细解析。如果该 Servlet 关联的是一个 jsp 文件,那么前面初始化的就是 JspServlet,接下去会模拟一次简单

25、请求,请求调用这个 jsp 文件,以便编译这个 jsp 文件为 class,并初始化这个 class。这样 Servlet 对象就初始化完成了,事实上 Servlet 从被 web.xml 中解析到完成初始化,这个过程非常复杂,中间有很多过程,包括各种容器状态的转化引起的监听事件的触发、各种访问权限的控制和一些不可预料的错误发生的判断行为等等。我们这里只抓了一些关键环节进行阐述,试图让大家有个总体脉络。下面是这个过程的一个完整的时序图,其中也省略了一些细节。图 4. 初始化 Servlet 的时序图(查看大图)回页首Servlet 体系结构我们知道 Java Web 应用是基于 Servlet

26、 规范运转的,那么 Servlet 本身又是如何运转的呢?为何要设计这样的体系结构。图 5.Servlet 顶层类关联图从上图可以看出 Servlet 规范就是基于这几个类运转的,与 Servlet 主动关联的是三个类,分别是 ServletConfig、ServletRequest 和 ServletResponse。这三个类都是通过容器传递给 Servlet 的,其中 ServletConfig 是在 Servlet 初始化时就传给 Servlet 了,而后两个是在请求达到时调用 Servlet 时传递过来的。我们很清楚 ServletRequest 和 ServletResponse 在

27、 Servlet 运行的意义,但是 ServletConfig 和 ServletContext 对 Servlet 有何价值?仔细查看 ServletConfig 接口中声明的方法发现,这些方法都是为了获取这个 Servlet 的一些配置属性,而这些配置属性可能在 Servlet 运行时被用到。而 ServletContext 又是干什么的呢? Servlet 的运行模式是一个典型的“握手型的交互式”运行模式。所谓“握手型的交互式”就是两个模块为了交换数据通常都会准备一个交易场景,这个场景一直跟随个这个交易过程直到这个交易完成为止。这个交易场景的初始化是根据这次交易对象指定的参数来定制的,这

28、些指定参数通常就会是一个配置类。所以对号入座,交易场景就由 ServletContext 来描述,而定制的参数集合就由 ServletConfig 来描述。而 ServletRequest 和 ServletResponse 就是要交互的具体对象了,它们通常都是作为运输工具来传递交互结果。ServletConfig 是在 Servlet init 时由容器传过来的,那么 ServletConfig 到底是个什么对象呢?下图是 ServletConfig 和 ServletContext 在 Tomcat 容器中的类关系图。图 6. ServletConfig 在容器中的类关联图上图可以看出 S

29、tandardWrapper 和 StandardWrapperFacade 都实现了 ServletConfig 接口,而 StandardWrapperFacade 是 StandardWrapper 门面类。所以传给 Servlet 的是 StandardWrapperFacade 对象,这个类能够保证从 StandardWrapper 中拿到 ServletConfig 所规定的数据,而又不把 ServletConfig 不关心的数据暴露给 Servlet。同样 ServletContext 也与 ServletConfig 有类似的结构,Servlet 中能拿到的 ServletCo

30、ntext 的实际对象也是 ApplicationContextFacade 对象。ApplicationContextFacade 同样保证 ServletContex 只能从容器中拿到它该拿的数据,它们都起到对数据的封装作用,它们使用的都是门面设计模式。通过 ServletContext 可以拿到 Context 容器中一些必要信息,比如应用的工作路径,容器支持的 Servlet 最小版本等。Servlet 中定义的两个 ServletRequest 和 ServletResponse 它们实际的对象又是什么呢?,我们在创建自己的 Servlet 类时通常使用的都是 HttpServlet

31、Request 和 HttpServletResponse,它们继承了 ServletRequest 和 ServletResponse。为何 Context 容器传过来的 ServletRequest、ServletResponse 可以被转化为 HttpServletRequest 和 HttpServletResponse 呢?图 7.Request 相关类结构图上图是 Tomcat 创建的 Request 和 Response 的类结构图。Tomcat 一接受到请求首先将会创建 org.apache.coyote.Request 和 org.apache.coyote.Response,这两个类是 Tomcat 内部使用的描述一次请求和相应的信息类它们是一个轻量级的类,它们作用就是在服务器接收到请求后,经过简单解析将这个请求快速的分配

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1