Servlet 3.0 公开预览版引发争论

  • Dio Synodinos
  • 崔康

2008 年 12 月 24 日

话题:Java社区语言 & 开发文化 & 方法

JSR-315发布了 Servlet3.0 规范的公开预览版,同时在GlassFish代码分支上提供了参考实现。这次发布引发了人们对于专家组(Expert Group)为下一代 Servlet API 和整个Java EE 6平台做出的各种选择的争论。

Servlet API 一直处于风口浪尖,从初期草稿开始,JSR 315 专家组致力于在类似便捷开发、插件性等领域完善和提高该规范,其领袖之一 Rajiv Mordani,这样说道:

  • 便捷开发 (Ease of Development):在早期草案中,我们添加了一些 注解,允许你像 POJO 一样写 Servlet。但是在专家组的若干次讨论和社区反馈之后,我们决定删除像 @GET, @POST 这样的方法层注解,保留 doGet、doPos 方法和扩展 HttpServlet 类。但是,那些重命名以更有效使用的最顶层注解仍然存在。 @WebServlet 用于声明一个 servlet,@ServletFilter 声明过滤器,@WebServletContextListener 定 义 ServletContextListener。除了这些注解,像 @Resource 这种自 Servlet2.5 就一直支持的注解则保持不变。
  • 可插入性:构建于 servlet 之上的 Web 框架在开发人员中很受欢迎,其中很多人提出了各种各样的问题。为了更好地支持框架便于开发人员编写 web 应用,我们在 servlet3.0 规范中添加一些方式以帮助开发人员根据自身情况使用和管理框架。
  • 异步处理:这是我们在 servlet3.0 规范中变化最大的部分。在早期草案中,我们暂停、重新开始、确定了我们定义的语义。但是,在这之后,专家组对于如何解决异步处理的各种用例进行了大量的讨论,规范中做出的修改现在也可以解决各种问题。

Roy Van Rijn 表达了他对于早期草案中出现的一些特性的担忧

我更倾向于完全不使用针对 GET/POST 方法的注解,但是我发现 Java EE 6 规范提倡使用类似的注解,JSR-315 的编写者“别无选择”(糟糕的借口)。我在本文中表达的观点已经发给了 JSR 组织,但至今没有回应。

我也找不到一名成员给出原因、解释、澄清等等。最近 Java EE 6 规范发布公开预览版,其中包含了对 Servlet 3.0 规范的引用,所以这会成为 Java EE 6 的一部分。但是我恳请他们花时间重新考虑关于注解的决定。

随着规范公开预览版的发布,来自 Webtide 的 Greg Wilkins认为该规范非常糟糕,是不和谐的专家组和有缺陷的流程的产物。他的主要观点包括:

  • 它代表了 API 设计上的一次思想实验,不关注实现的复杂性、试用可行性和社区反馈。
  • 要求测试实现的请求被拒绝了。
  • 没有公开的或者合理的机制来收集来自社区的需求和宝贵的社区咨询。
  • 一些模糊的需求(比如包装的异步请求)在较晚时候包含进来,没有用例和用户需求。
  • 写的非常糟糕,就像大多数 JCP 文档一样。
  • 一些新的特性引起了安全隐患,并可能导致部署缓慢。
  • 异步 servlet 的建议被改变了,与早期草案不同。最初的方法是Jetty Continuations的结果,从 2008 年 3 月即可在 Jetty-7 pre-release 中试用,已经在很多框架和应用中测试过,包括ometdDWRJSFBlazeDS

Greg 总结说:

我相信在现在的预览版中有明显的错误,这些缺陷已经多的让人很容易就可以发现。当我从专家组收到关于这些问题的支持信息时,我无法确信规范领袖的合法身份,我可能因为过于严厉而无法得到帮助了。

Rajiv 对 Greg 的答复中指出:

  • 在 GlassFish 中有相关实现。
  • 他从没看到过 Greg 的请求。
  • 如果不喜欢新功能,可以禁止使用。
  • 没有明显的证据表明部署会变慢。
  • 异步 servlet 增加的方式更被社区所喜欢,他引用了专家组的邮件。

Rajiv 也提到了来自 RedHat 的 Bill Burke 写的一篇博文,其中

他批评了 Jetty 6 中的异步 servlet 实现

随后,Greg Wilkins 宣布他致力于 Servlet 3.0 异步 servlet 的一个实现,他在博客上列举了一些修正 / 扩展和与专家组的持续讨论。其中包括:

  • 新的异步分发器类型(ASYNC DispatcherType ),用于分发异步请求。
  • 当请求分发时,isAsyncStarted() 方法为 false。
  • 如果 getReader() 或者 getOutputStream() 已经被调用,则调用 startAsync() 或者 startAsync(request.response) 时会抛出 IllegalStateException 异常。这可以把异步处理器限制到简单的情 况下。
  • 如果通过 startAsync(request,response) 启动异步模式,在 AsyncContext 上使用任何 forward(...) 方法都会有 IllegalStateException 异常。这避免了分发包装器的复杂,但允许异步处理器使用包装器。
  • forward(path) 和 forward(context,path) 方法还没有实现。

代码可以从Jetty 分支servlet-api 分支中得到。

Grep 谈到了异步 servlet 的事情:

虽然还需要更多测试,但是这个代码已经实现了基本的异步行为,不需要很复杂的重新分发请求或者前递方法。我相信这代表了 3.0 的合理折中方案。在我们从 3.0 的简单子集里获得经验之后,如果需要更多的特性,可以添加到 3.1 中。

您可以在 InfoQ 上找到更多关于ServletsGlassFishJettyCometJava EE 的信息。

查看英文原文:Servlet 3.0 Public Review Sparks a Debate

Java社区语言 & 开发文化 & 方法