servlet2.3规范之二——Servlet接口

2 Servlet接口

Servlet接口是servlet API的主要抽象。所有servlet或者直接实现该接口,或者更常见的继承一个实现该接口的类。servlet API中有两个类实现了servlet接口,为GenericServletHttpServlet。大多数情况下,开发人员将继承HttpServlet以实现他们的servlet

2.1 请求处理方法

Servlet接口定义了一个service方法来处理客户端请求。当servlet容器将每个请求传递给servlet实例时都会调用该方法。

Web应用处理并发请求通常要求web开发人员设计servletservice方法可以多线程执行。

通常web容器通过不同线程并发执行service方法,处理对于同一个servlet的并发请求。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.1.1</span></strong></chsdate> HTTP专有请求处理方法

HttpServlet抽象子类在Servlet接口基础上还添加了一些附加方法,由HttpServlet类的service方法自动调用,以处理基于HTTP的请求。这些方法是:

doGet处理HTTP GET请求

doPost处理HTTP POST请求

doPut处理HTTP PUT请求

doDelete处理HTTP DELETE请求

doHead处理HTTP HEAD请求

doOptions处理HTTP OPTIONS请求

doTrace处理HTTP TRACE请求

通常在开发基于HTTPservlet时,servlet开发人员自身只需要关心doGetdoPost方法。其他方法只为非常熟悉HTTP编程的程序员们使用。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.1.2</span></strong></chsdate> 附加方法

doPutdoDelete方法允许Servlet开发人员支持采用这些特性的HTTP/1.1客户端。HttpServlet doHead方法是一种特殊的doGet方法,只返回doGet方法生成的headerdoOptions方法返回servlet支持的所有HTTP方法。doTrace方法生成的响应,包含TRACE请求中发送的所有header实例。

对于只支持HTTP/1.0的容器,只支持doGetdoHeaddoPost方法,因为HTTP/1.0没有定义PUTDELETEOPTIONSTRACE方法。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.1.3</span></strong></chsdate> 有条件的GET支持

HttpServlet接口定义了getLastModified方法以支持有条件的GET操作。一个有条件的GET操作所请求的资源,只有在指定时间内被修改才被发送。在适当的情况下,该方法的实现可能会有效地利用网络资源。

2.2 实例数

正如第13章“部署描述符”所述,作为含servletweb应用部署描述符一部分的Servlet声明,控制着servlet容器如何提供servlet实例。

对于一个不驻留于分布式环境(默认)的servlet而言,servlet容器必须保证每个servlet声明只使用一个实例。不过,对于实现SingleThreadModel接口的servlet而言,servlet容器可以实例化多个实例以处理繁重的请求加载,但是一个特定实例只能一次处理请求。

如果作为应用一部分的servlet被部署为分布式,部署描述符中标明,那么容器只能让每个虚拟机(VM)每个servlet声明持有一个实例。不过,如果分布式应用中的servlet实现了SingleThreadModel接口,那么容器可以让容器中每个VM实例化多个servlet实例。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.2.1</span></strong></chsdate> 单线程模型注意点

使用SingleThreadModel接口保证一次只能有一个线程执行指定的servlet实例的service方法。要注意这项保证只适用于每个servlet实例,因为容器可以选择池化这些对象。这些对象一次可以被多个servlet实例访问,比如HttpSession实例,在任意时刻对于多个servlet都是可用的,即使它实现了SingleThreadModel

2.3 servlet生命周期

servlet通过定义生命周期来进行管理,包括如何加载,实例化与初始化,处理客户端的请求,以及如何撤销服务。生命周期在API中表示为javax.servlet.Servlet接口的initservicedestroy方法,所有servlet必须直接实现或者通过GenericServletHttpServlet抽象类间接实现。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.1</span></strong></chsdate> 加载和实例化

servlet容器负责加载和实例化servlet。加载和实例化可以在容器启动时进行,也可以延迟到容器认为需要servlet来处理请求时。

当容器引擎启动时,servlet容器必须能定位所需要的servlet类。Servlet容器使用通常的Java类加载工具加载servlet类。可以从本地文件系统,远程文件系统或者其他网络服务中加载。

加载Servlet类后,容器将它实例化。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.2</span></strong></chsdate> 初始化

servlet对象实例化之后,容器必须在它能处理客户端请求之前将其初始化。初始化是为了servlet能够读取持久性的配置数据,初始化代价高的资源(比如基于JDBC连接),以及执行其他一次动作。容器通过调用Servlet接口的init方法,并使用实现ServletConfig接口的单个(每个servlet声明)对象来初始化servlet实例。配置对象允许servlet访问来自web应用配置信息的名-值初始化参数,还允许servlet访问一个实现ServletContext接口的对象,它描述servlet运行时环境。关于ServletContext接口的更多信息参见第3章“Servlet上下文”。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><em><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.2</span></em></strong></chsdate>.1 初始化的错误情形

在初始化过程中,servlet实例可能抛出UnavailableException或者ServletException异常。在这种情况下,servlet不可以被放入激活的服务中,而必须由servlet容器释放。因为它被看成是不成功的初始化,因此不会调用destroy方法。

在初始化失败之后,容器可以重新实例化并初始化一个实例。例外的是,当UnavailableException异常指出了不可用的最小时间,容器必须在创建并初始化一个新的servlet实例之前等待这段时间。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><em><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.2</span></em></strong></chsdate>.2 工具考虑

当工具加载并内省web应用而触发静态初始方法和调用nit方法有明显不同。开发人员不应当假定servlet处于激活的容器运行时中,除非调用了Servlet接口的init方法。比如,当只有静态(类)初始化方法被调用时,servlet不要试图建立与数据库或者EJB容器的连接。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.3</span></strong></chsdate> 请求处理

servlet正确初始化之后,servlet容器就可以使用它来处理客户端请求。请求表示为ServletRequest类型的request对象。Servlet通过调用提供的ServletResponse类型对象的方法来填充该请求的响应。这些对象作为参数传递给Servlet接口的service方法。

HTTP请求中,容器提供的对象类型为HttpServletRequestHttpServletResponse

注意由servlet容器放入服务的servlet实例可能在生命周期中并不处理请求。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><em><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.3</span></em></strong></chsdate>.1 多线程问题

servlet容器可以向servletservice方法发送并发请求。要处理这些请求,servlet的开发人员必须采取措施,使得在service方法中可以多线程同时处理。

开发人员可以采用的一个替代方案是实现SingleThreadModel接口,它要求容器保证service方法中一次只有一个请求线程。Servlet容器可能通过串行化servlet的请求,或者维持一个servlet实例池来满足这项需求。如果servlet所属的web应用被标记为分布式的,容器可以在应用分布的每个VM中维持一个servlet实例池。

对于没有实现SingleThreadModel接口的servlet,如果service方法(或者HttpServlet抽象类的service方法分发的doGetdoPost方法)使用了synchronized关键字,那么servlet容器不能使用实例池方案,而是必须依次处理请求。强烈推荐开发人员不要在这些情况下同步service方法(或者它所分发的方法),因为对性能有影响。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><em><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.3</span></em></strong></chsdate>.2 请求处理中的异常

Servlet可能在处理请求中抛出ServletExceptionUnavailableException异常。ServletException异常表示在请求处理中有错误出现,容器应当采取相应的错误来清除该请求。

UnavailableException异常表示servlet暂时或者永久不能处理请求。

如果是UnavailableException异常所表示的永久不可用,servlet容器必须从服务中删除servlet,调用它的destroy方法,并释放servlet实例。

如果是UnavailableException异常所表示的暂时不可用,那么容器可以选择在暂时不可用期间不发送任何请求到servlet。在此期间容器拒绝的任何请求必须返回SERVICE_UNAVAILABLE (503)响应状态,同时在Retry-After header中指明不可用何时结束。

容器可以选择忽略永久和暂时不可用之间的区别,将所有UnavailableException异常当成永久不可用,从而从服务中将抛出任何UnavailableException异常的servlet删除。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><em><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.3</span></em></strong></chsdate>.3 线程安全

requestresponse对象的实现并不保证线程安全。这意味着它们应当只在处理线程的请求作用域内使用。

requestresponse对象不可以被其他线程中执行的对象所引用,因为这将引起不能预期的后果。

<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False"><strong><span lang="EN-US" style="FONT-SIZE: 11pt; mso-font-kerning: 0pt">2.3.4</span></strong></chsdate> 服务终止

Servlet容器并不要求任意时间段保持servlet加载。servlet容器中的servlet实例可能只保持激活状态几毫秒,或者是servlet容器的生命周期(这可能是几天,几月或者几年),或者是两者之间的任何时间段。

servlet容器决定要从服务中删除一个servlet时,调用Servlet接口的destroy方法,来让servlet释放它正使用的所有资源,并保存所有持久化的状态。比如,容器想保存内存资源,或者自身被关闭时可以这样做。

servlet容器调用destroy方法之前,它必须允许当前运行在servletservice方法内的所有线程完成执行动作,或者延长服务器定义的时限。

一旦servlet实例调用destroy方法,容器不可以发送其他请求到该servlet实例。如果容器需要再次启用servlet,它必须重新创建一个servlet类的实例。

完成destroy方法后,servlet容器必须释放servlet实例,以便垃圾回收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值