大多数 Java Web 框架都构建于 Servlet API 之上,并且除了依赖于 WEB-INF/lib 目录之外,还需要你在应用程序的 web.xml 中配置一个或者多个 Servlet、过滤器或监听器。JSR-315,即 Servlet 3.0 规范,计划将成为 JEE 6 的一部分。它在试图改变这种现状。规范目前还处于早期的草案阶段,可以在这里下载并审阅。
为了达到零配置和可插拔的目标,规范中建议了几种新特性,其中包括:
- Annotation(注释):Servlet 3.0 规范引入了大量新的 Annotation,比如 @Servlet,它为 Servlet 提供了 url-mapping 信息——@Servlet(url-mapping=”/foo”);@ServletFilter,它与 @FilterMapping 一起使用,可以定义 Web 应用程序中的过滤器。
- 支持 web.xml 片段(flag):其中包含 Servlet、过滤器和监听器的定义,可以与 web.xml 合并到一起,允许 Web 框架将所需的控件打包到一个 jar 中,这样使用起来可以更容易。
新规范使用一个 metadata-complete(完全使用 metadata 的)标记来控制 Annotation 与 web.xml 片段的查找。这些特性在专家组内部正在引发激烈的争论,有些人担心这会带来严重的安全风险,比如无意或者故意地部署了非预期的 Filter 和 Servlet。还有一些争论是围绕这些新特性是否足够灵活展开的。最后,专家组在等待来自社区的反馈。Greg Wilkins 在他的 Blog 中详细描述了他所关心的问题,特别提到了 Web 片段的自动查找与合并,并列出了三种可能的方案之一:使用可选的
“如果没有 web.xml 或者 3.0 web.xml 中没有列出任何包含项,在当前提议的草案中,默认情况下会完整查找 WEB-INF 以发现被标注过(annotated)的 Servlet 和 Filter、TLD 监听器和 web.xml 片段。但是,如果 web.xml 包含了
元素,发现过程将被改变,如下例所示:
这些
表明只需要在 dwr.jar 和 cometd.jar 扫描 Annotation、TLD 片段和 web.xml 片段,而在 WEB-INF/classes 中扫描注释过的 Servlet。容器不会再扫描其他的类或者 jar,除非在 web.xml 的某个地方将它们列在 include 元素中。”
Rajiv Mordani 对规范提出了质疑:
“实际上,Greg Wilkins 提出的 include 方案的好处非常有限,尤其是人们主要的关注点有时是在 Servlet 和 Filter 是否在用户没有预期的情况下被暴露出去。我认为确保没有特定类型的组件被暴露应该是框架开发者的工作,而不是框架使用者的事情。通过使用一个标签来控制查找,你可以有效地获得 include 机制的功能,唯一的例外是,你无法只针对某个特定的 Jar 包集合进行查找。不过,利用 include 机制列出你希望查找的 jar,可能只会令描述符变得更复杂。”
在今年的 JavaOne 大会上,专家组讨论了另外两种可能的方案。其一是除了 metadata-complete 标记外,再引入第二个标记,用来激活 / 禁用 web 片段和启用 / 关闭 Web 片断的查找,以及其他 Annotation 的功能。但是,正如 Rajiv Mordani 指出的,Annotation 机制已经可以通过 web.xml 文件被覆写,提供一个更合理的控制的级别:
“如果使用 Annotation 声明 Servlet 和 Filter,相应的 Servlet/Filter 就必须有一个 url-mapping/FilterMapping 属性。按照这种方式,如果没有显式的映射,要暴露哪个 Servlet,是没有任何约定的。同时,如果考虑到 Java EE 平台的其他部分,尤其是 EJB 和 Web Service 这类技术,那么部署描述符过去经常会覆盖 Annotation 中设置的信息…如果你不想让容器处理任何 Annotation,而是想通过部署描述符确定所有的配置信息,那么就像 Java EE 5 平台的其他部分一样,我们的描述符中有一个 metadata-complete 元素。如果这个元素存在并且设置为‘true’,容器将不会处理任何 Annotation 的信息,仅仅使用描述符中指定的配置信息。处于性能和安全性的考量,这种方法可以关闭自动查找行为。”
另一个选择是提供一种机制在应用程序的 web.xml 中禁用 Servlet 和 Filter,这样任何在生产环境中不需要的 Servlet,都可以应用程序的主 web.xml 来禁用,例如:
<pre id="jb1a26"> <servlet> <br id="jb1a27"></br> <servlet-name>FrameworkServlet</servlet-name> <br id="jb1a28"></br> <enabled>false</enabled> <br id="jb1a29"></br> </servlet>
可以把你的反馈发送到专家组 jsr-315-comments@jcp.org 。
评论