Servlet规范之Web应用

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet规范之Web应用相关的知识,希望对你有一定的参考价值。

Web Applications

文章是对 JSR-000340 JavaTM Servlet 3.1 Final Release的Java™ Servlet规范的翻译,尚未校准

文章目录


一个Web应用是由servlets、html页面、类和其他资源组成的集合,这些资源在Web服务器上构成一个完整的应用。Web应用程序可以被捆绑在多个供应商的不同容器上运行。

Web应用服务器中的Web应用

一个网络应用程序根目录是网络服务器中的一个特定路径。例如,一个目录应用程序可以位于http://www.mycorp.com/catalog。所有以这个前缀开始的请求将被路由到代表目录应用程序的ServletContext。

一个Servlet容器可以建立自动生成Web应用程序的规则。例如,一个~user/的映射可以用来映射到基于/home/user/public_html/的Web应用。

默认情况下,一个Web应用程序的实例必须在任何时候都在一个虚拟机上运行。如果应用程序通过其部署描述符被标记为 “分布式”,这一行为可以被覆盖。被标记为分布式的应用程序必须遵守一套比普通Web应用程序更严格的规则。这些规则在本规范中被列出。

与ServletContext的关系

servlet容器必须在Web应用程序和ServletContext之间强制执行一对一的通信。ServletContext对象提供了一个servlet及其应用程序视图。

Web应用的要素

一个Web应用程序可能由以下项目组成:

  • Servlets
  • JSP™ Pages1
  • Utility Classes 实用工具类
  • Static documents (HTML, images, sounds, etc.) 静态文件(HTML,图像,声音等)
  • Client side Java applets, beans, and classes 客户端的Java小程序、beans和classes
  • Descriptive meta information that ties all of the above elements together 将上述所有元素联系起来的描述性元信息

部署层次结构

本规范定义了一个用于部署和打包的分层结构,它可以存在于一个开放的文件系统中,也可以存在于一个归档文件中,或者以其他形式存在。建议(但不是必须)Servlet容器支持这种结构作为运行时表示。

目录结构

一个Web应用程序是作为一个结构化的目录层次存在的。这个层次结构的根目录作为文件的根目录,是应用程序的一部分。例如,对于一个Web容器中上下文路径为/catalog的Web应用程序,位于Web应用程序层次结构底部的index.html文件,或在WEB-INF/lib中的JAR文件中包括META-INF/resources目录下的index.html,可以被用来满足来自/catalog/index.html的请求。如果index.html同时存在于根上下文和WEB-INF/lib目录下的JAR文件的META-INF/resources目录中,那么必须使用根上下文中的文件。匹配URL和上下文路径的规则在第12章 "Mapping Requests to Servlets"中列出。由于应用程序的上下文路径决定了Web应用程序内容的URL命名空间,Web容器必须拒绝定义了可能导致该URL命名空间潜在冲突的上下文路径的Web应用程序。这可能会发生,例如,试图部署具有相同上下文路径的第二个Web应用程序。由于请求是以区分大小写的方式与资源匹配的,因此对潜在冲突的判断也必须以区分大小写的方式进行。

在应用程序的层次结构中存在一个特殊的目录,名为WEB-INF。这个目录包含了所有与应用程序相关的、不在应用程序的文档根目录中的东西。大多数WEB-INF节点不是应用程序的公共文档树的一部分。除了静态资源和打包在驻留在WEB-INF/lib目录下的JAR文件的META-INF/resources中的JSP文件外,WEB-INF目录中包含的其他文件都不能由容器直接提供给客户端。然而,WEB-INF目录中的内容对Servlet代码来说是可见的,可以使用 ServletContext上的 getResourcegetResourceAsStream方法调用,也可以使用 RequestDispatcher调用公开。因此,如果应用开发者需要从servlet代码中访问他不希望直接暴露给Web客户端的应用特定配置信息,他可以将其放在这个目录下。由于请求是以区分大小写的方式与资源映射相匹配的,例如,客户对/WEB-INF/foo/WEbiNf/ foo的请求不应该导致位于/WEB-INF下的Web应用程序的内容被返回,也不会导致任何形式的目录列表。

WEB-INF目录的内容如下:

  • /WEB-INF/web.xml部署描述符。
  • /WEB-INF/classes/目录用于Servlet和实用类。这个目录中的类必须对应用程序类加载器可用。
  • /WEB-INF/lib/*.jar区域用于Java ARchive文件。这些文件包含了打包在JAR文件中的Servlets、Bean、静态资源和JSP,以及其他对Web应用有用的实用类。网络应用程序类加载器必须能够从任何这些归档文件中加载类。

Web应用程序类加载器必须首先从WEB-INF/classes目录下加载类,然后再从WEB-INF/lib目录下的库JARs中加载。另外,除了静态资源被打包在JAR文件中的情况,任何来自客户端的访问WEB-INF/目录中的资源的请求必须以SC_NOT_FOUND(404)响应返回。

应用程序目录结构示例

下面是一个web应用程序中所有文件的示例。

/index.html
/howto.jsp
/feedback.jsp
/images/banner.gif
/images/jumping.gif
/WEB-INF/web.xml
/WEB-INF/lib/jspbean.jar
/WEB-INF/lib/catalog.jar!/METAINF/
resources/catalog/moreOffers/books.html
/WEB-INF/classes/com/mycorp/servlets/MyServlet.class
/WEB-INF/classes/com/mycorp/util/MyUtils.class

Web应用程序归档文件

Web应用程序可以使用标准的Java归档工具打包并签署成Web ARchive格式(WAR)文件。例如,一个用于问题跟踪的应用程序可以在一个名为issuetrack.war的归档文件中发布。

当打包成这种形式时,会有一个META-INF目录,其中包含对Java归档工具有用的信息。这个目录不能被容器作为内容直接提供给Web客户端的请求,尽管它的内容可以通过ServletContext上的getResourcegetResourceAsStream调用而被Servlet代码看到。另外,任何访问META-INF目录中的资源的请求都必须以SC_NOT_FOUND(404)响应返回。

Web应用程序部署描述文件

Web应用程序部署描述符(见第14章,“Deployment Descriptor”)包括以下类型的配置和部署信息:

  • ServletContext Init Parameters ServletContext的初始化参数
  • Session Configuration Session配置
  • Servlet/JSP Definitions Servlet/JSP的定义
  • Servlet/JSP Mappings Servlet JSP的映射
  • MIME Type Mappings MIME类型映射
  • Welcome File list 欢迎文件列表
  • Error Pages 错误页面
  • Security 安全

扩展的依赖关系

当一些应用程序使用相同的代码或资源时,它们通常会被作为库文件安装在容器中。这些文件通常是常见的或标准的API,可以在不牺牲可移植性的情况下使用。只有一个或几个应用程序使用的文件将被作为Web应用程序的一部分提供给人们访问。容器必须为这些库提供一个目录。放在这个目录中的文件必须在所有 Web 应用程序中可用。这个目录的位置是特定于容器的。Servlet 容器用于加载这些库文件的类加载器必须对同一 JVM 中的所有 Web 应用程序相同。这个类加载器实例必须是Web应用程序类加载器的父类加载器链中的某个地方。

应用程序开发人员需要知道Web容器上安装了哪些扩展,而容器需要知道WAR中的servlets对这种库有哪些依赖性,以便保持可移植性。

依赖于这种扩展或扩展的应用开发者必须在WAR文件中提供一个META-INF/MANIFEST.MF条目,列出WAR所需要的所有扩展。清单条目的格式应遵循标准的JAR清单格式。在部署Web应用程序期间,Web容器必须按照可选包版本机制(http://java.sun.com/j2se/1.4/docs/guide/extensions/)定义的规则,为应用程序提供正确的扩展版本。

Web 容器还必须能够识别 WAR 中 WEB-INF/lib 项下的任何库 JAR 的清单条目中所表达的声明依赖关系。

如果Web容器不能满足以这种方式声明的依赖关系,它应该用一个信息性的错误信息拒绝该应用程序。

Web应用程序类加载器

容器用来加载WAR中的servlet的类加载器必须允许开发者按照正常的Java SE语义使用getResource加载WAR中的库JAR中包含的任何资源。如Java EE许可协议所述,不属于Java EE产品的servlet容器不应允许应用程序覆盖Java SE平台的类,如java.*javax.*命名空间中的类,因为Java SE不允许修改。容器不应允许应用程序覆盖或访问容器的实现类。我们还建议实现应用程序的类加载器,以便在加载 WAR 中打包的类和资源时优先于驻留在容器范围的库 JAR 中的类和资源。一个实现还必须保证,对于部署在容器中的每个 Web 应用程序,调用必须返回一个 ClassLoader实例,该实例实现了本节中指定的契约。此外,ClassLoader实例必须是每个部署的 Web 应用程序的单独实例。在向 Web 应用程序进行任何回调(包括监听器回调)之前,容器需要如上所述设置线程上下文 ClassLoader,并在回调返回后将其设置为原始的 ClassLoader

更新Web应用

服务器应该能够在不重启容器的情况下用新的版本替换一个应用程序。当一个应用程序被替换时,容器应该提供一个强大的方法来保存该应用程序中的会话数据。

错误处理

请求属性

一个Web应用程序必须能够指定,当错误发生时,应用程序中的其他资源被用来提供错误响应的内容体。这些资源的指定是在部署描述符中完成的。

如果错误处理程序的位置是一个Servlet或JSP页面:

  • 由容器创建的原始的未包装的请求和响应对象被传递给servlet或JSP页面。
  • 请求路径和属性被设置,就像对错误资源进行的RequestDispatcher.forward一样。

The request attributes in TABLE 10-1 must be set.

TABLE 10-1 Request Attributes and their types

Request AttributesType
javax.servlet.error.status_codejava.lang.Integer
javax.servlet.error.exception_typejava.lang.Class
javax.servlet.error.messagejava.lang.String
javax.servlet.error.exceptionjava.lang.Throwable
javax.servlet.error.request_urijava.lang.String
javax.servlet.error.servlet_namejava.lang.String

这些属性允许servlet根据状态代码、异常类型、错误信息、传播的异常对象和发生错误的servlet所处理的请求的URI(由getRequestURI调用确定)以及发生错误的servlet的逻辑名称来产生专门的内容。

随着异常对象被引入本规范2.3版的属性列表,异常类型和错误信息属性是多余的。保留它们是为了向后兼容早期版本的API。

错误页面

为了让开发者能够在servlet产生错误时自定义返回给Web客户端的内容的外观,部署描述符定义了一个错误页面描述的列表。该语法允许配置资源,以便在Servlet或过滤器对特定状态代码的响应调用sendError时,或者在Servlet产生异常或错误并传播到容器时,由容器返回。

如果在响应上调用了sendError方法,容器就会查询使用状态代码语法的Web应用程序的错误页面声明列表,并尝试进行匹配。如果有匹配的,容器就会返回位置项所指示的资源。

在处理请求的过程中,servlet或过滤器可能会出现以下异常。

  • 运行时异常或错误
  • ServletExceptions或其子类
  • IOExceptions或其子类

Web应用程序可能已经使用exception-type元素声明了错误页面。在这种情况下,容器通过比较抛出的异常和使用exception-type元素的错误页面定义的列表来匹配异常类型。匹配的结果是容器返回位置条目中指示的资源。在类的层次结构中,最接近的匹配者将被返回。

如果没有包含exception-typeerror-page声明适合使用classhierarchy匹配,并且抛出的异常是ServletException或其子类,容器会提取被包装的异常,如ServletException.getRootCause方法所定义。对错误页面声明进行第二次传递,再次尝试与错误页面声明进行匹配,但使用被包装的异常。

在部署描述符中使用exception-type元素的错误页声明必须是唯一的,直到异常类型的类名。同样地,使用status-code元素的错误页面声明在部署描述符中必须是唯一的,直到状态代码。

如果部署描述符中的error-page元素不包含exception-typeerror-code元素,该错误页就是默认的错误页。当使用RequestDispatcherfilter.doFilter方法调用时,所述的错误页机制不干预错误的发生。这样一来,使用RequestDispatcher的过滤器或servlet就有机会处理产生的错误。

如果servlet产生的错误没有被上述的错误页面机制处理,容器必须确保发送一个状态为500的响应。

默认的servlet和容器将使用sendError方法来发送4xx和5xx状态的响应,这样就可以调用错误机制了。默认的servlet和容器将使用setStatus方法来发送2xx和3xx的响应,并且不会调用错误页面机制。

如果应用程序使用第 2-10 页的第 2.3.3.3 节 "Asynchronous processing"中描述的异步操作,那么应用程序就有责任处理应用程序创建的线程中的所有错误。容器可能负责处理通过 AsyncContext.start 发布的线程中的错误。关于在 AsyncContext.dispatch过程中发生的错误的处理,请参见第 2-16 页,“在执行调度方法时可能发生的任何错误或异常都必须由容器捕获和处理:”

错误Filters

错误页面机制在由容器创建的原始未包装/未过滤的请求和响应对象上操作。第 6.2.5 节 "Filters and the RequestDispatcher"中描述的机制可以用来指定在生成错误响应之前应用的过滤器。

欢迎文件

Web 应用程序开发者可以在 Web 应用程序部署描述符中定义一个称为欢迎文件的部分 URI 的有序列表。该列表的部署描述符语法在Web应用程序部署描述符模式中描述。

这种机制的目的是允许部署者为容器指定一个有序的部分URI列表,以便在出现对URI的请求时用于附加到URI,该URI对应于WAR中未映射到Web组件的目录条目。这种请求被称为有效的部分请求。

这个功能的使用通过下面的普通例子变得很清楚。一个index.html的欢迎文件可以被定义,这样一个对host:port/webapp/directory/这样的URL的请求,其中directory是WAR中没有被映射到servlet或JSP页面的条目,被返回到客户端为
host:port/webapp/directory/index.html

如果 Web 容器收到一个有效的部分请求,Web 容器必须检查部署描述符中定义的欢迎文件列表。Web 服务器必须按照部署描述符中指定的顺序将每个欢迎文件附加到部分请求中,并检查 WAR 中的静态资源是否被映射到该请求的 URI。如果没有找到匹配的文件,Web服务器必须再次按照部署描述符中指定的顺序将每个欢迎文件追加到部分请求中,并检查是否有一个Servlet被映射到该请求URI。Web 容器必须将请求发送到 WAR 中第一个匹配的资源。容器可以通过转发、重定向或与直接请求没有区别的容器特定机制将请求发送到欢迎资源。

如果没有按所述方式找到匹配的欢迎文件,容器可以用它认为合适的方式来处理该请求。对于某些配置来说,这可能意味着返回一个目录列表,或者对于其他配置来说,返回一个404响应。

考虑一个Web应用程序:

  • The deployment descriptor lists the following welcome files.部署描述符列出了以下欢迎文件。
<welcome-file-list>
	<welcome-file>index.html</welcome-file>
	<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
  • The static content in the WAR is as follows WAR中的静态内容如下
/foo/index.html
/foo/default.jsp
/foo/orderform.html
/foo/home.gif
/catalog/default.jsp
/catalog/products/shop.jsp
/catalog/products/register.jsp
  • 一个/foo的请求URI将被重定向到一个/foo/的URI。
  • /foo/的请求URI将被返回为/foo/index.html
  • 一个/catalog的请求URI将被重定向到一个/catalog/的URI。
  • 一个/catalog/的请求URI将被返回为/catalog/default.jsp
  • 一个请求的URI为/catalog/index.html将导致404 not found
  • 一个/catalog/products的请求URI将被重定向到/catalog/products/的URI。
  • /catalog/products/的请求URI将被传递给 "默认"servlet,如果有的话。如果没有映射 "默认"servlet,该请求可能会导致404未找到,可能会导致包括shop.jspregister.jsp在内的目录列表,或者可能导致容器定义的其他行为。关于 "默认"servlet的定义,见第12.2节 “Specification of Mappings”。
  • 上述所有的静态内容也可以打包在一个JAR文件中,上面列出的内容被打包在jar文件的META-INF/resources目录下。然后该JAR文件可以包含在Web应用程序的WEB-INF/lib目录中。

Web应用程序环境

不属于Java EE技术兼容实现的Servlet容器被鼓励(但不是必需的)实现第15.2.2节“Web Application Environment and the Java EE specification”中描述的应用程序环境功能。如果它们没有实现支持此环境所需的设施,那么在部署依赖于它们的应用程序时,容器应该提供警告。

Web应用程序部署

当Web应用程序被部署到容器中时,在Web应用程序开始处理客户端请求之前,必须按照这个顺序执行以下步骤。

  • 对部署描述符中的<listener>元素所标识的每个事件监听器实例进行实例化。
  • 对于实现了ServletContextListener的实例化监听器实例,调用contextInitialized()方法。
  • 对部署描述符中的<filter>元素识别的每个过滤器实例进行实例化,并调用每个过滤器实例的init()方法。
  • 按照load-on-startup元素值定义的顺序,实例化由<servlet>元素识别的每个Servlet的实例,其中包括<load-on-startup>元素,并调用每个Servlet实例的init()方法。

包含web.xml部署描述符

如果一个Web应用程序不包含任何Servlet、Filter或Listener组件或使用注解来声明这些组件,则不需要包含web.xml。换句话说,一个只包含静态文件或JSP页面的应用程序不需要有web.xml的存在。

以上是关于Servlet规范之Web应用的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot之增加一个Servlet

Servlet监听器技术

Servlet规范之过滤器Filter

高性能Web服务之tomcat基础应用详解

Servlet3.0新特性之web-fragment.xml模块化配置文件

Servlet规范之应用生命周期事件