Servlet规范

原文地址:

http://ajava.org/readbook/J2EE/srqcj2eejg/14338.html

6.2  Servlet规范

6.2.1  Servlet的发展史

Servlet是运行在Web服务器上的Java程序,用于响应客户请求。也可以说,Servlet是Java组件,部署在Web服务器上,能在请求/响应通信模式下有效地工作。

GenericServlet是独立于协议的Servlet。因此按照需要扩展GenericServlet后也可以实现与协议相关的Servlet。HttpServlet就是一个典型的例子,它扩展了GenericServlet,并将HTTP作为通信协议。

1997年中期,Servlet作为Web服务器组件被推出。现在,Servlet已成为稳定有效的Web组件,能有效替代Web服务器CGI程序。在1999年12月推出Servlet 2.2版后,Servlet得到广泛运用,Servlet规范也随之发展。2001年9月发布的Servlet 2.3版是Servlet规范发展史上又一里程碑式的事件。

下面的描述重点参照Servlet 2.3文档的Servlet规范,并将介绍Servlet 2.4这一新版本的一些特性。

6.2.2  Servlet规范详解

Servlet规范文档详细介绍了Servlet Web组件规范及其他所有相关信息。由于篇幅所限,本章仅围绕以下几个主题简要描述Servlet规范。

●     Servlet接口

●     Servlet上下文

●     请求

●     响应

●     过滤

●     会话

●     应用程序生命期事件

●     安全性

●     部署描述符[3]

除上述内容外,规范文档还讨论API,详细描述Java类及接口。

1. Servlet接口

这一部分规范文档讨论了Servlet本身的一些重要方面。可使用以下两种方式之一创建Servlet:

●     实现Servlet接口

●     扩展的GenericServlet类或HttpServlet类

在创建Servlet后,还要描述Servlet细节,以及在运行时环境中,Servlet及Web应用程序中其他关联Web组件的附加信息。规范将XML文档中嵌入的这些信息称为部署描述符,供Web容器在部署组件时使用。在创建和部署Servlet 后,Servlet成为Web服务器“容器”中的“实例”。

Web组件设计人员可按照设计标准,选择创建以下两类Servlet:

●     多线程Servlet

●     单线程Servlet

如图6-4所示,在默认情况下,“多线程Servlet”是Web服务器“容器”的“单个实例”,Web容器将所有客户请求转发给一个实例。规范也允许创建多个Servlet实例,以便为各个客户请求提供服务,此时的Servlet类需要实现 SingleThreadModel接口。

图6-4  多线程Servlet。在本图中,一个Servlet实例为3个具体客户请求生成3个不同“线程”。

若请求数量更多,这个Servlet实例可生成更多的线程

图6-5所示为根据访问Web应用程序的客户数量创建的多个Servlet实例。由于实现Single ThreadModel的Servlet需要创建多个Servlet实例,厂商可池化这些对象,利用池对象获得实例。Web应用设计人员需要根据企业的整体应用程序需要,选择合理的Servlet创建模型,即默认多线程模型或单线程模型。Servlet容器(和Servlet引擎)厂商需要确保合理地加载和实例化Servlet。第一种方法是在部署期间,在启动容器本身时,由Servlet引擎加载和实例化Servlet;第二种方法是在第一个客户请求到达容器时,加载和实例化Servlet。

图6-5  实现SingleThreadModel接口的Servlet。本例中为3个不同请求创

     建了3个不同的Servlet实例。Servlet实例将随请求数量而增加

Servlet生命期

如图6-6所示,Web容器Servlet组件的生命期可分为3个阶段。

●     Servlet开始

●     Servlet服务

●     Servlet结束

图6-6  Servlet组件的生命期。Servlet会经历一个简单的生命历程。init()方法使Servlet进入“就绪”

   状态。之后,Servlet可接收服务请求。当容器决定销毁Servlet时,将调用destroy()方法

 

 

Servlet开始。init()方法由容器调用,只运行一次,使Servlet进入“就绪”状态。这个过程称作Servlet初始化。如果开始阶段出现异常,Servlet将不能响应任何用户请求。

在初始化过程中,init()方法使用ServletConfig对象。ServletConfig包含Servlet需要的初始化参数的名-值对。通常,目录、文件路径及其他资源信息将写入这个对象。

未初始化的Servlet由容器卸载,不经历通常定义的Servlet生命期。容器不会为这样的 Servlet运行destroy()方法,并可能在未来重新加载Servlet。如图6-7所示,未初始化的Servlet不能接收客户端的任何请求,Web容器将截获准备传给Servlet的任何请求,并向请求客户端返回异常。

图6-7  未初始化的Servlet不能接收客户端的任何请求。要使Servlet响应请求,就必须成功运行init()

方法。如果在运行init()方法前发出请求,或出现其他临时或永久的问题,容器将截获请求,并向

客户端发送对应的消息

Servlet服务在正确初始化Servlet后,Servlet就可以接收客户端服务请求了。Servlet容器可能通过Servlet的service()方法发送多个并发请求,为此,开发人员在设计service()方法时,需要考虑并发处理多个线程,还要注意灵活地“同步”全部或部分service()方法,尽量避免性能的大幅下降。在Servlet生命期,服务线程的执行可能引发异常。

在出现异常时,Servlet会变得临时不可用,个别情况下甚至长期不可用。如果长期不可用,则容器必须运行Servlet的destroy()方法,并释放资源。如果Servlet仅是临时不可用,容器将异常返回给客户端,并显示消息,要求在一定时间后重试。

图6-8演示了一个正常初始化的Servlet与客户端通信的行为。

图6-8  全面初始化的Servlet可用来服务客户请求。本图的Servlet已完全初始化,并做好服务请求的

准备。Servlet接收请求,并发回响应。为简化起见,这里未考虑Servlet线程方面的事项

Servlet析构容器可在任意长的时间内使用一个 Servlet实例,或SingleThreadModel Servlet的多个实例。Servlet实例可一直延续到Servlet容器(或Web服务器)本身的生命期结束为止。当容器认定不再需要某个 Servlet时,可以调用Servlet的destroy()方法,释放Servlet占用的所有容器资源。不过,容器不能调用活动Servlet的 destroy()方法。在调用Servlet的destroy()方法前,容器需要确保以下两点:

●     阻塞更多新请求

●     完成所有待处理请求

在图6-9中,容器阻塞了对正在被销毁的Servlet调用。

图6-9  正被销毁的Servlet不支持任何客户请求,在容器启动了destroy()方法后,

 将阻塞客户端对Servlet实例的更多请求,并向客户端发回合理响应

Servlet上下文

Web服务器能支持若干Web应用程序。每个Web应用程序又能支持一个或多个Servlet。同一个Web 应用程序的多个Servlet需要共享Web应用程序环境的资源。为此,Servlet规范提供了ServletContext接口。如图6-10所示,Servlet可利用ServletContext对象执行登录事件,获得资源的URL索引,也可设置和存储Web应用程序需要的属性。对于 ServletContext而言,最重要的上下文信息包括:

●     初始化参数

●     上下文属性

●     资源

图6-10  Web应用程序环境和ServletContext API。这里将Web应用程序表示为一个包含相关Servlet

        的“文件夹”。本例的Web应用程序有两个Servlet,支持3个ServletContext变量:ver1、

ver2和ver3。这些属性及值供Web应用程序的两个Servlet共享

初始化参数。初始化参数用来初始化Web应用程序,而不是前面“Servlet开始”区域讨论的单个Servlet。这些参数由部署描述符中的“键-值”对提供。

ServletContext API允许通过getInitParameter()和getInitParameterNames()等方法访问这些初始化参数。

上下文属性。上下文属性是一组应用程序属性,由Web应用程序的Servlet共享。可设置和获得参数,也可通过编程方法,从Web应用程序中删除上下文属性。ServletContext API允许通过多种方法访问上下文属性,如setAttribute()、getAttribute()、removeAttribute()和 getAttributeNames()等。

资源。“静态”内容文件的层次,是Web应用程序的一部分,被称为“Web应用程序资源”,包括HTML、GIF和JPEG等文件。ServletContext API允许通过多种方法访问这些资源,例如getResource()和getResourceAsStream()等。

请求

Servlet的服务方法有权访问请求对象ServletRequest或HttpServletRequest。请求对象包含客户请求及其他一些相关信息。该对象将用作传给service()方法的两个参数中的第一个参数。

请求参数采用“键-值”对格式。在特定环境下,一些键可能有多个值。图6-11显示了发送给在Web服务器环境下执行的Servlet的客户请求。HttpServletRequest对象的几个重要方面如下:

●     属性

●     头

●     Cookie

图6-11  客户请求和HttpServletRequest对象:任何客户请求都作为HttpServletRequest对象传给Servlet。

Servlet使用HttpServletRequest API,如getAttribute()或getIntHeader()等处理请求

属性。属性是与HttpServletRequest对象相关的对象。与HttpServletRequest一样,属性也采用“键-值”对形式;与HttpServletRequest的不同之处在于,一个属性只能有一个值。

HttpServletRequest API允许通过多种方法访问这些属性,如getAttribute()、setAttribute()和getAttributeNames()等。

头。头是HTTP请求的一部分。Servlet可通过HttpServletRequest API方法,如getHeader()、getHeaders()或getHeaderNames()等访问这些头信息。

这些HttpServletRequest对象的的头可能包含integer和(或)date的文本表示。为了访问它们,HttpServletRequest API提供了getIntHeader()和getDateHeader()等方法。

CookieHTTP请求通常伴随着一个或多个Cookie。这些Cookie包含宝贵数据。如果客户端和服务器应用程序之间需要多次请求/响应操作,则Cookie可以帮助Web应用程序构建客户端和服务器应用之间的会话。HttpServletRequest API提供诸如getCookies()的方法,以便访问Cookie,并创建和维护会话。

响应

Servlet的服务方法有权访问响应对象。响应对象将是ServletResponse或 HttpServlet Response。该对象包含了响应客户端的信息和所有其他相关细节,是service()方法两个参数中的第二个参数。客户端响应打包在 HttpServletResponse对象中。HttpServletResponse对象的重要组成部分有:

●     头

●     缓冲区

●     响应类型和格式

图6-12显示了从Servlet到客户端的响应。

图6-12  HttpServletResponse对象和客户端响应:对客户端的任何响应都包含在Servlet的

HttpServletResponse对象中。Servlet使用适当的API,如getWriter()、setContentType()

和setContentLength()等响应客户端

头。发送给客户端的头信息可通过HttpServletResponse API获得。诸如addHeader()的方法可用于创建发送给客户端的头信息。同样,setHeader()方法可用于设置相应头的头值。对于特定的数据类型,如integer和date,HttpServletResponse API提供了addIntHeader()、setIntHeader()、addDateHeader()和setDateHeader()等方法。

缓冲区。Servlet容器可以提供缓冲区功能,以增强“请求-响应”操作的性能和效率。一些缓冲区功能可通过setBufferSize()、getBufferSize()、isCommitted()、reset()、 resetBuffer()和flushBuffer()等方法实现。

响应类型和格式。发送给客户端的输出需要进行相应设置和简化。为此,HttpServlet Response API提供了以下方法:setContentType()、setContentLength()、getWriter()和getOutput Stream()等。开发人员需要根据setContentType()方法设置的内容类型设置响应格式。

例如,若setContentType()方法被设置为text/html类型,开发人员就需要根据业务需求设置相应的输出格式。编程人员在设计应用程序时,要认真选择输出的内容类型。开发人员还要理解输出的表示部分,并全面了解HTML等表示语言的语法。

完成了HttpServletResponse对象就意味着service()方法执行结束。在关闭响应时,Servlet容器必须清空客户响应缓冲区剩余的所有内容。

2. 过滤

过滤(filtering)是Servlet 2.3版的新特性。过滤器(Filter)是轻量级Web组件,能及时转换HttpServletRequest和 HttpServletResponse对象的头和内容。Filter和Servlet都是Web应用程序的一部分,都用生命期方法管理。

顾名思义,Filter为Servlet的请求/响应操作提供过滤服务。如图6-13所示,过滤器可以“过滤”传给Servlet的请求,也可以“过滤”将要从Servlet发送到客户端的响应。它们不仅处理静态内容,也处理动态内容。

图6-13  Servlet组件“过滤”请求。Filter可对请求和响应做预处理和后期处理。Filter是特殊的Servlet, 

   本图将它们显示为带孔的Servlet。Filter在适当处理请求后,将请求转发给相应的Servlet

Web应用程序可用的一些过滤组件如下:

●     身份验证Filter

●     加密Filter

●     转换Filter

Filter开发人员可通过实现Filter接口创建Filter。与Servlet一样,Filter的相关信息也在部署描述符中提供。可通过定义部署描述符中的“Filter-映射”元素配置Filter或一些相关Filter的集合,以方便调用。

Filter的生命期。Filter组件的生命期与Servlet的类似。图6-14所示为Filter的生命期。有3个方法用来管理Filter生命期,如下:

●     init()方法

●     doFilter()方法

●     destroy()方法

图6-14  Filter组件的生命期。Filter组件的生命期与Servlet相似,

区别仅表现在doFilter()方法的设计和实现上

init()方法用FilterConfig对象初始化Filter。如果初始化成功,那么就做好了在“请求 /响应”操作上执行过滤操作的准备。当容器收到客户请求时,将使用Filter列表中的第一个Filter实例,并调用doFilter()方法。 doFilter()方法会接收3个对象:HttpServletRequest、HttpServletResponse和FilterChain。可按以下方法使用Web应用程序的Filter组件:

●     分析HTTP请求的头

●     可能用HttpServletRequest的定制实现包装请求对象,以适当修改头或数据

●     可能用HttpServletRequest的定制实现包装响应对象,以适当修改头或数据

●     可能调用Filter链的下一项,下一项可能是另一个Filter,也可能是Servlet

图6-15所示为一个Filter链,及其与Web层的Servlet等组件的交互。

图6-15  Web应用程序环境中的Filter链组件。Filter的显著优势在于拥有恰到好处的链式处理能力,

允许利用可重用组件方便地组装Web应用程序

会话。这一部分规范旨在将客户端绑定到特殊“会话”,以便将从客户端到Web应用程序的一系列请求/响应操作视为最终事务的组成部分。这需要做一些工作,因为从设计上讲,HTTP是一个无状态协议。

Servlet支持以下会话跟踪机制:

●     Cookie

●     HTTP会话

●     URL重写

虽然Cookie是简明直观的会话构建方式,但规范推荐将“URL重写”作为最小公分母,当然,浏览器的用户也可关闭这个选项,以接收Cookie。开发人员需要精心设计客户端需要的“会话”。

为客户端构建和管理会话需要考虑以下方面:

●     创建一个“新”会话

●     客户端试图加入并继续参与“当前”会话

●     “完成”会话

对于具体企业应用程序而言,会话的构建取决于企业的业务需要,开发人员应选择适当选项,以确保会话的构建和管理。

本规范有助于创建一个名为HttpSession的对象,Web应用程序可为特殊会话相应地使用 HttpSession。可将一些会话需要的属性绑定到这个对象。在设置属性或取消属性时,可能需要通知参与Web应用程序会话的某些对象,HttpSession API提供了通知方式。

在用HttpSession对象创建和处理会话时,开发人员同样需要精心设计,以正确处理几个问题,如分布式环境、多线程和超时等。HttpSession API提供了必要的方法,如getID()、isNew()、getAttribute()、setAttribute()、 removeAttribute()、getCreationTime()、getLastAccessedTime()、 getMaxInactiveInterval()、setMaxInactiveInterval()和invalidate()等。

3. 应用程序生命期事件

与Servlet生命期不同,应用程序生命期指整个Web应用程序的生命期。应用程序生命期事件是Servlet 2.3版的新特性。如图6-15所示,Web应用程序周期的两个主要事件是:

●     应用程序启动

●     应用程序关闭

对于Web应用程序而言,由ServletContext定义的上下文以及由HttpSession定义的会话都非常重要。它们会影响整个Web应用程序,而不限于单个Servlet或其他Web组件。新规范为ServletContext和 HttpSession确定了两个监听者(Listener)接口集。ServletContextListener接口用于处理 ServletContext的生命期,而HttPSessionListener接口用于处理HttpSession的生命期。同样,ServletContextAttributeListener和HttpSessionAttri- buteListener接口也有助于跟踪与它们各自的属性相关的事件。

4. 安全性

大多数企业应用程序都在Internet上部署运行,故有必要营造一个安全环境,以便用户在企业应用程序上安全地执行交易。任何企业应用程序都需要以下一些基本安全功能:

●     身份验证

●     访问控制

●     数据完整性

●     保密性

可通过组合使用以下两种方式确保Web应用程序的安全性:

●     声明性安全

●     编程性安全

声明性安全为Web应用程序提供粗粒度安全保护,而编程性安全允许对Web应用程序的安全性进行更周详的控制。

Web应用程序的声明性安全通过部署描述符实现,将程序的安全性编写为XML文档,形成部署描述符的一部分。而编程性安全使用API对安全性进行精细控制,getRemoteUser()、isUserInRole()和getUserPrincipal()等都是有用的方法。

5. 部署描述符

部署描述符就像Web应用程序的“万年历”。Servlet 2.3版要求使用必需的部署描述符,以记录Web应用程序的重要方面:

●     Servlet声明

●     Servlet映射

●     ServletContext初始化参数

●     会话声明

●     应用程序生命期监听者声明

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值