一个 Web 应用是由许多 servlet、 HTML 页面、类和其余资源组成的集合,这些资源组成了一个运行在 Web
服务器上的完整应用程序。 Web 应用程序可以捆绑和运行在来自不一样提供商的不一样容器上。html
在 Web 服务器中 Web 应用程序的根目录是一个特定的路径。例如,一个 catalog 应用,能够位于
http://www.mycorp.com/catalog
。以这个前缀开始的全部请求将被路由到表明 catalog 应用的 ServletContext
环境中。java
servlet 容器可以制定 Web 应用程序自动生成的规则。例如,一个~user/
映射可用于映射到一个基于/home/user/public_html/
的 Web 应用。web
默认状况下,在任什么时候候一个 Web 应用程序的实例必须运行在一个虚拟机( VM)中。若是应用程序经过其部署描述文件标记为“分布式”的,那么能够覆盖此行为。标记为分布式的应用程序必须遵照比普通的 Web应用程序更严格的规则。本规范中陈述了这些规则。安全
ServletContext
的关系servlet 容器必须强制 web 应用程序和ServletContext
之间一对一进行通讯。ServletContext
对象提供了一个servlet 和它的应用程序视图。服务器
Web 应用程序可能包括如下项目:app
本规范定义了一个用于部署和打包用途的,可存在于开放文件系统、归档文件或一些其余形式中的层次结构。建议 servlet 容器支持这种结构做为运行时表示形式,但不是必须的。webapp
一个 Web 应用程序以结构化的目录层次结构存在。层次结构的根目录做为文件的归档目录,这些文件是应用的一部分。例如,对于 Web 容器中一个 Web 应用程序的上下文路径/catalog
,在 Web 应用程序层次结构中的 index.html
文件,或在 WEB-INF/lib
目录下的 JAR 文件中的 META-INF/resources
目录下包括的index.html
文件,能够知足从/catalog/index.html
送达的请求。若是在根上下文中和应用的 WEB-INF/lib
目录下的 JAR 文件中的 META-INF/resources
目录中都存在一个 index.html
文件,那么必须使用根上下文中的index.html
。匹配的 URL 到上下文路径的规则安排在第 12 章: “请求映射servlet”中。因为应用的上下文路径肯定了 Web 应用内容的 URL 命名空间, Web 容器必须拒绝 Web 应用定义的上下文路径,由于可能在这个 URL 命名空间中致使潜在的冲突。例如,试图部署两个具备相同上下文路径的 Web 应用时可能发生这种状况。因为把请求匹配到资源是区分大小写的,因此在肯定潜在冲突时也必须区分大小写。异步
应用程序层次结构中存在一个名为“WEB-INF
”的特殊目录。这个目录包含了与应用程序相关的全部东西,这些东西不在应用程序的归档目录中。大多数 WEB-INF 节点都不是应用程序公共文档树的一部分。除了静态资源和 WEB-INF/lib
目录下打包在 JAR 文件中 META-INF/resources
目录下的 JSP 文件以外, WEB-INF目录下包含的其余任何文件都不能由容器直接提供给客户端访问。然而, WEB-INF 目录中的内容能够经过 servlet 代 码 调 用 ServletContext
的 getResource
和 getResourceAsStream
方 法 来 访 问 , 并 可 使 用RequestDispatcher
调用公开这些内容。所以,若是应用开发人员想经过 servlet 代码访问这些内容,而不肯意直接对客户端公开应用程序指定配置信息,那么能够把它放在这个目录下。因为把请求匹配到资源的映射区分大小写,例如,客户端请求‘/WEB-INF/foo
’, ‘/WEb-iNf/foo
’,不该该返回位于/WEB-INF 下的 Web 应用程序的内容,也不该该返回其中任何形式的目录列表。jsp
WEB-INF 目录中的内容有:分布式
/WEB-INF/web.xml
部署描述文件。/WEB-INF/classes/
。此目录中的类对应用程序类加载器必须是可见的。/WEB-INF/lib/*.jar
。这些文件中包括了 servlet, beans,静态资源和打包在 JAR 文件中的 JSP 文件,以及其余对 Web 应用程序有用的实用工具类。 Web 应用程序的类加载器必须可以从这些归档文件中加载类。Web 应用程序类加载器必须先从 WEB-INF/classes
目录下加载类,而后从 WEB-INF/lib
目录下的 JAR 库中加载。此外,除了静态资源打包在 JAR 文件中的状况外,任何来自客户端的请求访问 WEB-INF/
目录中的资源必须返回一个 SC_NOT_FOUND
( 404)的响应。
下面是一个示例 Web 应用程序的文件清单:
/ |-/index.html |-/howto.jsp |-/feedback.jsp |-/images |-/banner.gif |-/jumping.gif /WEB-INF |-/web.xml |-/lib |-/jspbean.jar |-/catalog.jar!/META-INF/resources/catalog/moreOffers/books.html |-/classes |-/com/mycorp/servlets/MyServlet.class |-/com/mycorp/util/MyUtils.class
可使用标准的 Java 归档工具把 Web 应用程序打包并签名到一个 Web 存档格式( WAR)文件中。例如,一个关于“issue tracking”的应用程序能够分布在一个称为 issuetrack.war
的归档文件中。
当打包成这种形式时,将生成一个 META-INF
目录,其中包含了对 java 归档工具备用的信息。尽管这个目录的内容能够经过 servlet 代码调用 ServletContext
的 getResource
和 getResourceAsStream
方法来访问,容器也不能把这个目录看成内容来响应客户端请求。此外,任何请求访问 META-INF
目录中的资源必须返回一个 SC_NOT_FOUND
( 404)的响应。
Web 应用程序部署描述文件(见第 14 章, “部署描述文件”)的配置和部署信息包括如下几种类型:
当许多应用程序使用相同的代码或资源,一般将它们安装在容器的库文件中。这些文件每每是通用的或标准的 API,能够在不牺牲可移植性的状况下使用。仅由一个或几个应用程序使用的文件将做为 Web 应用程序的一部分来访问。容器必须为这些库提供一个目录。放置在这个目录中的文件必须对全部的 Web 应用可
见。此目录的位置由容器指定。 servlet 容器用于加载这些库文件的类加载器必须和在同一个 JVM 中的全部 Web 应用的类加载器相同。这个类加载器的实例必须在 Web 应用程序类加载器的父类加载器链中。
为了保持可移植性,应用程序开发人员须要知道 Web 容器中安装了哪些扩展,而容器须要知道 WAR 中的servlet 依赖哪些库。
依 赖 这 样 的 扩 展 的 应 用 开 发 人 员 必 须 在 WAR 文 件 中 提 供 一 个 列 出 所 有 WAR 文 件 所 需 扩 展 的META-INF/MANIFEST.MF
文件。清单文件的格式应该遵循标准的 JAR 清单格式。在部署 Web 应用程序的时候, Web 容器必须使正确的扩展版本对遵循可选包版本控制( Optional Package Versioning)机制 定义的规则的应用程序可见。
Web 容器也必须可以识别出 WAR 文件中 WEB-INF/lib
目录下的任意一个 JAR 包中的清单文件声明的依赖关系。
若是 Web 容器不可以知足以这种方式声明的依赖关系,它应该使用一条有意义的错误消息拒绝该应用程序。
容器用于加载 WAR 文件中 servlet 的类加载器必须容许开发人员使用 getResource
加载遵循正常 JavaSE 语义的 WAR 文件的 JAR 包中包含的任何资源。和 Java EE 许可协议中描述的同样,不属于 Java EE 产品的 servlet 容器不该该容许应用程序覆盖 Java SE 平台中的类,如在 java.
和 javax.
命名空间中的类, Java SE不容许进行修改。容器不该该容许应用程序覆盖或访问容器的实现类。同时建议应用程序类加载器实现成WAR 文件中的类和资源优先于属于容器范围内的 JAR 包中的类和资源加载。一个类加载器的实现必须保证对部署到容器的每一个 web 应用,调用 Thread.currentThread.getContextClassLoader()
返回一个实现了本节规定的约定的 ClassLoader
实例。此外,部署的每一个 Web 应用程序的 ClassLoader
实例必须是一个单独的实例。容器必须在任何回调(包括侦听器回调)到 Web 应用程序以前设置上面描述的线程上下文ClassLoader
,一旦回调返回,须要把它设置成原来的 ClassLoader
。
服务器应该可以更新一个新版本的应用程序,而无需重启容器。当一个应用程序更新时,容器应提供一个可靠的方法来保存该应用程序的会话数据。
在发生错误时, Web 应用程序必须可以详细说明,应用程序中的其余资源被用来提供错误响应的内容主体。这些资源的规定在部署描述文件中配置。
若是错误处理位于一个 servlet 或 JSP 页面:
RequestDispatcher.forward
跳转到已经完成的错误资源同样。表 10-1 请求属性和它们的类型
请求属性 | 类型 |
---|---|
javax.servlet.error.status_code | java.lang.Integer |
javax.servlet.error.exception_type | java.lang.Class |
javax.servlet.error.message | java.lang.Class |
javax.servlet.error.exception | java.lang.Throwable |
javax.servlet.error.request_uri | java.lang.String |
javax.servlet.error.servlet_name | java.lang.String |
这些属性容许 servlet 根据状态码、异常类型、错误消息、传播的异常对象、发生错误时由 servlet 处理的请求 URI(像调用 getRequestURI 方法肯定的 URI 同样)、以及发生错误的 servlet 的逻辑名称来生成专门的内容。
因为本规范的 2.3 版本引入了异常对象属性列表,异常类型和错误消息属性是多余的。他们保留向后兼容早期的 API 版本。
为了使开发人员可以在 servlet 产生一个错误时自定义内容的外观返回到 Web 客户端,部署描述文件中定义了一组错误页面说明。这种语法容许当 servlet 或过滤器调用 response 的 sendError
方法指定状态码时,或若是 servlet 产生一个异常或错误传播给容器时,由容器返回资源配置。
若是调用 response 的 sendError
方法,容器参照为 Web 应用声明的错误页面列表,使用状态码语法并试图匹配一个错误页面。若是找到一个匹配的错误页面,容器返回这个位置条目指示的资源。
在处理请求的时候 servlet 或过滤器可能会抛出如下异常:
ServletException
或它的子类异常IOException
或它的子类异常Web 应用程序可使用 exception-type
元素声明错误页面。在这种状况下,容器经过比较抛出的异常与使用 exception-type
元素定义的 error-page
列表来匹配异常类型。在容器中的匹配结果返回这个位置条目指示的资源。在类层次中最接近的匹配将被返回。
如 果 声 明 的 error-page
中 没 有 包含 exception-type
适 合使 用 的 类 层 次 结 构 的 匹 配 , 那 么 抛 出 一 个 ServletException
异常或它的子类异常,容器经过 ServletException.getRootCause
方法提取包装的异常。第二遍经过修改错误页面声明,使用包装的异常再次尝试匹配声明的错误页面。
使用 exception-type
元素声明的 error-page
在部署描述文件中必须惟一的,由 exception-type
的类名决定它的惟一性。一样地, 使用 status-code
元素声明的 error-page
在部署描述文件中必须是惟一的,由状态码决定它的惟一性。
若是部署描述中的一个 error-page
元素没包含一个 exception-type
或 error-code
元素,错误页面时默认的错误页面。
当错误发生时,错误页面机制不会干预调用使用 RequestDispatcher
或 filter.doFilter
方法。用这种方法,过滤器或 Servlet 有机会使用 RequestDispatcher
处理产生的错误。
若是上述错误页面机制没有处理 servlet 产生的错误,那么容器必须确保发送一个状态 500
的响应。
默认的 servlet 和容器将使用 sendError
方法,发送 4xx
和 5xx
状态的响应,这样错误机制才可能会被调用。
默认的 servlet 和容器将使用 setStatus
方法,设置 2xx
和 3xx
的响应,并不会调用错误页面机制。
若是应用程序使用第 2.3.3.3 节,第 2-10 页“异步处理”中描述的异步操做,那么处理应用程序建立的线程的全部错误是应用程序的职责。容器应该经过 AsyncContext.start
方法注意线程发出的错误。对于处理AsyncContext.dispatch
过程当中发生的错误,请参照第 2-16 页中看到的几节, “执行 dispatch
方法的时候可能发生的错误或异常必须被容器按照以下的方式捕获并处理”。
错误页面机制运行在由容器建立的原来未包装过的或未通过过滤的 request 或 response 对象上。在第 6.2.5 节“过滤器和请求转发”中描述的机制能够在产生一个错误响应以前用来指定要应用的过滤器。
Web 应用程序开发人员能够在 Web 应用程序部署描述文件中定义一个称为欢迎文件的局部 URI 有序列表。在 Web 应用程序部署描述文件模式中描述了部署描述文件中欢迎文件列表的语法。
这种机制的目的是,当一个对应到 WAR 文件中一个目录条目的请求 URI 没有映射到一个 Web 组件时,容许部署者为容器用于添加 URI 指定局部 URI 有序列表。这种请求被认为是有效的局部请求。
通 过 下 面 常 见 的 例 子 来 明 确 这 种 用 法 的 便 利 : 可 以 定 义‘index.html
’ 欢 迎 文 件 , 以 便 像 请 求 URL host:port/webapp/directory/
,其中‘directory
’是 WAR 文件中的一个不能映射到 servlet 或 JSP 页面的条目,如下面的形式返回给客户端: ‘host:port/webapp/directory/index.html
’。
若是 Web 容器接收到一个有效的局部请求, Web 容器必须检查部署描述文件中定义的欢迎文件列表。欢迎文件列表是一个没有尾随或前导 /
的局部 URL 有序列表。 Web 服务器必须把部署描述文件中按指定顺序的每一个欢迎文件添加到局部请求,并检查 WAR 文件中的静态资源是否映射到请求 URI。 Web 服务器必须再
把部署描述文件中按指定顺序的每一个欢迎文件添加到局部请求,并检查 servlet 是否映射到请求 URI。 Web 容器必须将请求发送到 WAR 文件中第一个匹配的资源。容器可以使用转发、重定向、或容器指定的机制将请求发送到欢迎资源,这与直接请求没有什么区别。
若是按上述的方式没有找到匹配的欢迎文件,容器可能会使用它认为合适的方式处理该请求。对于有的配置来讲,这可能意味着返回一个目录列表,对其余配置来讲可能返回一个 404
响应。
考虑一个 Web 应用程序:
部署描述文件列出了如下的欢迎文件。
<welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list>
WAR 文件中的静态内容以下
/foo/index.html /foo/default.jsp /foo/orderform.html /foo/home.gif /catalog/default.jsp /catalog/products/shop.jsp /catalog/products/register.jsp
请求 URI /foo
将被重定向到 URI /foo/
。
请求 URI /foo/
将返回/foo/index.html
的。
请求 URI /catalog
将被重定向到 URI /catalog/
。
请求 URI /catalog/
将返回/catalog/default.jsp
。
请求 URI /catalog/index.html
将致使 404
未找到错误。
请求 URI /catalog/products
将重定向到 URI /catalog/products/
。
请求 URI /catalog/products/
将被传递给“默认”的 servlet(若是有默认的 servlet 的话)。若是没有映射到“默认”的 servlet,请求可能会致使一个 404
未找到错误,可能会致使一个包括 shop.jsp
和 register.jsp
目录列表,或可能致使容器定义的其余行为。请参见 12.2 节, “映射规范”定义的“默认”servlet。
全部上述的静态内容均可以打包到 JAR 文件的 META-INF/resources
目录中。这个 JAR 文件能够放到 Web
应用的 WEB-INF/lib
目录下。
servlet 容器不属于 JavaEE 技术标准的实现,鼓励实现这个容器但不是必需的,实现应用环境的功能请参见第 15.2.2 节中描述的“Web 应用环境”和 JavaEE 规范。若是他们没有实现须要支持这种环境的条件,根据部署依赖它们的应用程序,容器应该提供一个警告。
当一个 Web 应用程序部署到容器中,在 Web 应用程序开始处理客户端请求以前,必须按照下述步骤顺序执行。
<listener>
元素标识的每一个事件监听器的一个实例。ServletContextListener
接口的监听器实例,调用 contextInitialized()
方法。<filter>
元素标识的每一个过滤器的一个实例,并调用每一个过滤器实例的 init()
方法。<load-on-startup>
元素的<servlet>
元素,根据 load-on-startup
元素值定义的顺序为每一个 servlet 实例化一个实例,并调用每一个 servlet 实例的 init()
方法。若是 Web 应用不包含任何 servlet、过滤器、或监听器组件或使用注解声明相同的,那么能够不须要 web.xml
文件。换句话说,只包含静态文件或 JSP 页面的应用程序并不须要一个 web.xml
的存在。