很多 Java Web 应用都是基于某个框架的,如 Apache Wicket、Java ServerFaces、Struts 或是 Spring MVC 等等。要想使用框架,开发者需要在应用的 web.xml 配置文件中注册框架的切入代码,如 Servlet、Filter 或是 Listener。这么做的后果就是部署描述符变得很庞大,同时导致框架所用的 XML 与特定于应用的 XML 混杂在了一起。Servlet 3.0 规范的一个主要目标就是让开发者无需编辑 web.xml 部署描述符就能部署 Servlet、Filter 和 Listener,同时可以将 web.xml 文件拆分成多个模块。为了实现这一点,Servlet 3.0 规范增加了基于注解的配置(@WebServlet、@ServletFilter 以及 @WebServletContextListener),这使得我们可以不再需要 web.xml 文件,同时规范还引入了一个新的概念:Web 片段(Web Fragment)。
Web 片段可以将框架的“样板”XML 与应用的其他配置分开,并且能够实现应用的自我注册。Web 片段必须放在名为 web-fragment.xml 的文件中,该文件只要位于 Web 应用的 classpath 下即可,但通常都将其放到 META-INF 目录下或是框架的 jar 文件中。XML 以
<web-fragment> <filter> <filter-name>MyXSSFilter</filter-name> <filter-class> MyXssFilter</filter-class> </filter> <servlet> <servlet-name>myFrameworkServlet</servlet-name> <servlet-class> MyFrameworkServlet</servlet-class> </servlet> <listener> <listener-class> MyFrameworkListener</listener-class> </listener> </web-fragment>
容器在部署时会处理 XML 片段并组装成最终的部署描述符。由于容器负责组装 web.xml 文件,因此如果需要按照特定的顺序来调用框架的 Servlet、Listener 或 Filter 时就可能产生问题。为了避免这个问题,Servlet 3.0 API 支持绝对与相对顺序的部署描述符。我们可以在 web.xml 文件中使用
由于既支持片段,又可以使用注解作为另一种配置机制,Servlet 3.0 可以插入框架的共享拷贝,比如JAX-WS、JAX-RS 以及JSF 等,他们都构建在Web 容器之上,使用了ServletContainerInitializers。这些框架是通过jar services API 被检测到的,同时还可以指定其处理的类型列表。对于WEB-INF/lib 下的任何jar 来说,只要其中包含的类被检测到都会传递给ServletContainerInitializer。这样,我们还可以将同样的API 作为ServletContextListeners。
从Servlet API 首次发布以来,构建Web 应用的方法发生了翻天覆地的变化,尤其是使用越来越多的异步Web 技术。这些技术(一般统称为Ajax 或是Web 2.0)对于Web 客户端(比如浏览器)与服务器端之间的传输机制产生了重要的影响,因为客户端会在一个页面中向服务器端发出更多的请求而不是每次请求都刷新一次页面。
长时间的服务器端处理会恶化这一情况,比如等待JDBC 连接池中的连接,或是等待JMS 队列中的消息等。在Servlet 中等待实在是太低效了,因为这种阻塞会消耗线程以及其他有限的系统资源。鉴于此,Servlet 3.0 引入了异步处理请求的功能,这样线程就可以返回到容器中并执行其他任务。在请求上的异步处理开始时,其他线程或是回调既可以生成响应,也可以分发请求以便通过AsyncContext.dispatch 方法在容器上下文中执行请求。
由于异步Servlet 的行为与同步的差别非常大,因此Servlet 3.0 要求开发者指定asyncSupported=true 以表示Servlet 支持异步请求。不仅是Servlet,Filter 也可以异步执行。Servlet 3.0 通过新的ServletRequest 方法来支持异步处理,比如startAsync() 会返回一个AsyncContext 对象,该对象用于持有传递给方法的request 与response 对象。这里,处理原始请求的线程还可以执行其他操作。此外,API 还引入了一个新的Listener 类:AsyncListener,它会告诉我们异步操作何时结束或者是否超时了。AsyncContext 类拥有一个complete() 方法,凭借该方法我们可以在异步操作结束后提交响应。AsyncListener 类拥有一个dispatch() 方法,它会将异步请求转发给容器,这样其他框架(比如JSP)就可以生成响应了。
除了引入大量的新技术和新方法外,Servlet 3.0 规范还对其他地方进行了大量的增强:HttpServletRequest 终于获得对multipart/form-data MIME 类型的内置支持了、Cookie 类开始支持“HttpOnly” cookie 以避免某些跨站点的脚本攻击、ServletContext API 也得到了更新,我们可以通过编程的方式将Servlet 和Filter 加到上下文中了。
查看英文原文: The Java EE 6 Web Tier: Servlets Gain Asynchronous Support, Improved Extensibility
评论