原创作者: sailor90   阅读:1345次   评论:1条   更新时间:2011-05-26    

SRV.2 The Servlet Interface

        Servlet接口是Java Servlet API的核心抽象。所有servlet都直接或者间接地实现了这个接口,更为普遍的是,继承自一个实现了此接口的类。在Java Servlet API中有两个类,GenericServlet和HttpServlet,它们继承了Servlet接口。通常,开发者会继承HttpServlet来实现他们的servlet。

 

SRV.2.1 Request Handling Methods

        基础的Servlet接口定义了一个service方法来处理客户端的request。Service方法在container把每个request路由至某个servlet实例时被调用。
        对于web应用程序来说,并发request的处理通常需要web container开发者设计的serlvet可以在某个特定时刻于service方法内处理多线程的执行。
        一般来说,web container对于同一个servlet处理并发requests,是通过在不同线程中同时执行service方法来实现的。

 

SRV.2.1.1 HTTP Specific Request Handling Method

HttpServlet的抽象子类与它相比,增加了额外的方法,这些方法会自动被service方法调用,如:

  • doGet用来处理HTTP GET request
  • doPost用来处理HTTP POST request

 

SRV.2.2 Number of Instances

        作为servlet container的web application的deployment descriptor的一部分,servlet声明控制着container怎样提供servlet的实例。关于servlet declaration的详细信息,参见Chapter SRV.13 Deployment Descriptor。
        在非分布式环境下,servlet container对于每个servlet declaration一定只对应一个实例。然而,当servlet实现了SingleThreadModel接口,container会创建多个实例来处理重量级的request访问,并且序列化request给某个实例。
        在分布式环境下,container会为每一个JVM的每一个servlet declaration创建唯一实例。不过,如果在分布式应用中的servlet实现了SingleThreadModel接口,container会在一个JVM中创建一个servlet的多个实例。

SRV.2.2.1 Note About The Single Thread Model

        SingleThreadModel接口保证了在同一时间内只有一个县城会执行给定servlet实例的service方法。需要特别注意的是这个保证值作用于每一个servlet实例,因为container可以选择将对象保存在池中,这些对象在同一时间内可以访问多个servlet实例,比如HttpSession的实例,可以在任何时间访问多个servlet,包括哪些实现了SingleThreadModel的servlet。
        推荐开发者选择其他方式去解决这些问题而不是去实现这个接口,比如避免实例变量的使用或对存取资源的代码使用同步代码块。SingleThreadModel接口在这个版本的规范中是不被推荐使用的。

 

 

SRV.2.3 Servlet Life Cycle

        Servlet通过完整生命周期定义被管理起来,这个生命周期定义了它如何被加载和创建、被初始化,如何处理来自client的请求,如何消亡。整个生命周期可以通过javax.servlet.Servlet接口API提供的方法init,service,destroy来表示,所有Servlet都必须直接或者间接通过GenerricServlet、HttpServlet抽象类来实现javax.servlet.Servlet。

 

SRV.2.3.1 Loading and Instantiation

        Container负责装在和实例化servlet。装载和实例化的时机,有可能是在container启动时,或者直到container确定有request需要这个servlet的服务的时候。
        当servlet引擎启动后,必要的servlet类一定会被servlet container加载。Servlet容器使用普通的java类加载设备加载servlet。加载可以来自本地文件系统,远程文件系统,或者其他网络服务。
        在载入Servlet类之后,container会实例化servlet以备使用。

 

SRV2.3.2 Initialization

        在servlet对象被实例化以后,container必须在它处理来自client的request之前做好它的初始化工作。在初始化时,servlet可以读取持久化配置数据,初始化昂贵的(costly)资源(比如基于JDBC的connection),并且执行其他一次性的动作。Container初始化servlet实例,通过调用Servlet接口的init方法,这个方法以唯一的(每个servlet声明一个)ServletConfig对象为参数。这个配置对象允许servlet从web application的配置中读取name-value的初始化参数信息。此配置对象使得servlet可以访问描述了servlet runtime environment的对象(实现了ServletContext接口的)。参见SRV.3 Servlet Context获得更多关于ServletContext的信息。

SRV.2.3.2.1 Error Conditions on Initialization

        在初始化的过程中,servlet实例有可能抛出UnavailableException或者ServletException。在这种情况下,servlet一定不会被置为有效的服务,并且一定会被container释放掉。在container认为初始化工作不成功的情况下,destroy方法不会被调用。
        在初始化失败后,container可以创建一个新的实例并且对它进行初始化。异常抛出的规则是:当UnavailableException抛出的次数达到不可用次数的下限,并且container处在等待创建并初始化一个新servlet实例的时刻。

SRV.2.3.2.2 Tool Considerations

        当工具加载并且introspect web application时,静态初始化方法的触发不同于init方法的调用。开发者应该知道servlet在init方法被调用之前是不会处于有效的container runtime中的。比如:当只有静态初始化方法被调用时,servlet不应试图建立数据库连接或者EJB container。

 

SRV.2.3.3 Request Handling

        在servlet被正确地初始化后,container就可以使用它来处理客户端request了。ServletRequest类型的对象用来表示request,ServletResponse类型的对象用来表示response。它们作为参数传递给Servlet接口的service方法。
        在HTTP request的情况下,container提供的对象的类型为HttpServletRequest和HttpServletResponse。
        需要注意的是,被servlet container放置到服务中的servlet实例有可能在他的生命周期里一个request都没处理。

SRV.2.3.3.1 Multithreading Issues

        Container可以向servlet的service方法发送并发的request,为了处理这些request,servlet开发者必须为service方法中的多线程并发处理做好充分的准备。
        尽管不是推荐的,但对于开发者来说,通过实现SingleThreadModel接口来要求container保证统一时刻内只有一个reqeust线程作用于service方法,仍然是一种选择。Servlet container可以满足这种要求,通过序列化访问servlet的request,或者通过维护一个servlet实例的对象池来实现。如果web应用程序已经被标记为分布式的,而servlet又是web应用程序的一部分,那么container可以在每一个JVM(JVM that the application is distributed across)上维护一个servlet的对象池。
        对于那些没有实现SingleThreadModel接口的,如果service方法(或doGet, doPost之类那些被dispatch到HttpServlet抽象类的service方法的方法)已经使用synchronized关键字定义,container就无法使用对象池的方法,但是一定会序列化request传入service。在这种情况下,强烈建议开发者不要synchronize service方法(或dispatch到它的方法),因为这对性能有不利的影响。

SRV.2.3.3.2 Exception During Request Handling

        在处理request的过程中,Servlet有可能会抛出ServletException或者UnavailableException。
ServletException被抛出说明在处理request的过程中出现了一些错误,并且container应该采取适当的措施来清理request。
        UnavailableException意味着servlet暂时或者永久性的无法处理request。
如果UnavailableException指出的是永久性不可用,container就会把servlet从service中移除,调用它的destroy方法并且释放这个servlet实例。由于这个原因导致被container拒绝的任何request,都会返回一个SC_NOT_FOUND(404) response。
        如果UnavailableException指出的是暂时性的不可用,container会选择在这个暂时无效的时期内不给servlet发送任何request。由于这个原因导致被container拒绝的任何request,都会返回一个SC_SERVICE_UNAVAILABLE(503) response,并附带一个在无效时间结束后重试的指示标题。
        Container有可能会选择忽略暂时性无效和永久性无效的区别,并且对待所有UnavailableException作为永久性无效,因此remove servlet并且抛出UnavailableException。

SRV.2.3.3.3 Thread Safety

        Request和Response对象的实现并不被保证是线程安全的。这意味着它们只应该在request处理线程内被使用(This means that they should only be used within the scope of the request handling thread)。
        Request对象和Response对象的引用不应该交给那些在其他线程里运行的对象,因为resulting behavior有可能是非确定的。如果应用程序创建的线程使用了container管理的对象,比如request对象或者response对象,那些必须只能在servlet的service方法生命周期中使用的对象,并且这样的线程本身的生命周期存在于serlvet的service方法之内,因为在service方法结束之后访问这些对象有可能导致某些不确定的问题。请注意request对象和response对象是非线程安全的。如果那些对象被使用在多线程中,操作应当被同步或者通过包装再使用来达到线程安全。例如,同步存取request attribute的方法的调用,或者在一个线程中给response使用本地输出流。

 

SRV.2.3.4 End of Service

        Servlet container并不用在任何特定的时间段保持一个servlet处于被加载的状态。在container中,一个servlet实例的生命周期 有可能只有几毫秒,也可能 和container的生命周期一样长,或者在这之间的某个时间段。
        当container确定一个servlet应该从service中被remove掉,它就会调用Servlet接口的destroy方法来使servlet释放它用到的任何资源,并保存所有持久化状态。比如,当container想要保存内存资源,或者被停掉的时候,container就可以这么做。
        在servlet container 调用destroy方法之前,它必须使这个servlet的service方法中所有当前在运行的线程都执行完毕,或在在server限定的时间内提前完成。
        一旦servlet实例的destroy方法被调用,container就不会再把其他的request转交给servlet实例了。如果container需要再次使用这个servlet,它必须重新new一个此servlet的实例。
        在destroy方法执行完毕后,container一定会释放这个servlet实例,以使垃圾回收能够顺利执行。

评论 共 1 条 请登录后发表评论
1 楼 hobitton 2010-10-11 15:32
翻译的不错,不知道为啥没有翻译完,有点疑问:
原文2.3.3.1中的“A servlet container may satisfy this requirement by serializing requests on a servlet, or by maintaining a pool of servlet instances.”我觉得不应该翻译成“Servlet container可以满足这种要求,通过序列化访问servlet的request,或者通过维护一个servlet实例的对象池来实现。”,其中的“序列化”应该翻译成“串行”吧?

发表评论

您还没有登录,请您登录后再发表评论

文章信息

  • sailor90在2010-05-11创建
  • sailor90在2011-05-26更新
  • 标签: servlet, specification, 规范
Global site tag (gtag.js) - Google Analytics