考虑一下从客户端传输到服务器的数据量有多大。从可用性的角度来看,用户在一个薄客户端浏览器上获得了富用户界面,无需安装任何东西。但是,当在服务器端扩展这些应用程序时就要付出代价了。ajax应用程序的典型容量规划数可能会是标准web应用程序的3到4倍。
有人可能会问:这对weblogic server有何影响?每个发送给weblogic的http请求都要使用一个执行线程。根据ajax编程的性质以及许多短期的请求会以轮询的形式不断发送的情况,该行为模式可能造成大量客户端请求不断冲击服务器的局面。多年来,weblogic都将这一问题考虑在内,并构建了一个相当棒的特性,即futureresponseservlet。该范型构建于异步servlet理念的基础之上。从版本6.1开始,该功能就允许开发人员提供真正异步的来自服务器的通知,而无需对事件进行客户端轮训并在服务器端使用执行线程。在9.x之前,bea还不急于公开该类。
如何在现实中利用该类呢?我们来看一个例子。假定业务需求是要构建一个基于web的应用程序,该应用程序以近乎实时的方式向服务器发送数据而无需刷新浏览器。这样的应用程序可以向服务器提交一个需要花很长时间处理的请求,而仍然能够接收到关于其状态的异步事件并监听事件。从技术角度来看,这有许多实现方法。其中一种方法就是使用一个与java servlet通信的java applet来获得异步信息。这是一种不错的方法,但是对于用户来说有些不太方便,因为他们必须下载一个jvm,还要下载一个applet到浏览器。此外,还必须维护一个从客户端到服务器的持久性套接字连接,以便接收异步消息。设想一下,如果有1000个用户使用该applet,那么就有1000个执行线程几乎是在空等着发送事件通知到客户端。当然了,还有其它方法,比如从applet或ajax应用程序构建轮询机制来定期检查新数据。而如果不经常接收到数据,那么轮询就显得无用了,而且还浪费了服务器资源,占用了执行线程。反之,服务器可以定期轮询,将事件传播回客户端,并维护套接字线程,而无需使用持久性执行线程。这非常类似于java nio的运行方式。理想情况下,我们都希望构建一个从服务器“异步”接收事件通知而无需在服务器端使用持久性执行线程的应用程序,不管它是一个applet还是一个基于ajax的薄web应用程序。
| 以下是引用片段: import java.io.ioexception; import java.io.printwriter; import java.util.date; import java.util.stack; import javax.servlet.servletexception; import javax.servlet.http.httpservletrequest; import weblogic.servlet.futureresponseservlet; import weblogic.servlet.futureservletresponse; // an asynchronousservlet that handles http requests from a "separate" thread and // not the execute thread used to invoke this servlet. public class asynchronousserverresponseservlet extends futureresponseservlet { private final notifier notifier; public asynchronousserverresponseservlet() { this.notifier = new notifier(); this.notifier.start(); } public void service(httpservletrequest request, futureservletresponse response) throws ioexception,servletexception { // push this client's request to a buffer and return immediately. // asynchronous processing occurs in the run method of the notifier thread notifier.poll(request, response); } class notifier extends thread { private static stack clients = new stack(); void poll (httpservletrequest request, futureservletresponse response) { clients.push(new client(request, response)); } public void run() { while (!clients.empty()) { client client = null; try{ client = (client) clients.pop(); printwriter pw = client.response.getwriter(); for(int j = 0; j < 10; j++) { pw.println("time is:" + new date() + ""); pw.flush(); } pw.close(); } catch(throwable t) { t.printstacktrace(); } finally { try { client.response.send(); } catch(ioexception ioe) { ioe.printstacktrace(); } } } } } // inner class that holds o-n to the clients http request and response class client { private httpservletrequest request; private futureservletresponse response; private client(httpservletrequest request, futureservletresponse response) { this.request = request; this.response = response; } } |
本文并不打算介绍如何构建ajax应用程序。这方面的文章已经有很多了。本文的重点在于讨论表示层(比如ajax、applet或者任何前端应用程序)的异步处理的重要性。清单1展示了一个例子。
可以看出,该例子非常简单。asynchronousserverresponseservlet类扩展了futureresponseservlet,并重写了service方法。只使用一个线程(即notifier类)来处理所有的客户端连接响应。对于每个http请求,servlet向notifier线程注册套接字连接,然后返回。异步事件被交付给客户端,而持久性套接字连接被维持。
单个线程可管理多个客户端连接!run()方法可用于根据某种消息选择条件回调事件到客户端。该例子只执行了一个服务器端的push操作,有些过分简单了。线程池可被用于某些类型的事件处理。
总而言之,在处理长期运行的任务时,futureresponseservlet是一个好特性,它允许开发人员提高性能,在独立的线程中处理响应,并将开销降至最低。在构建异步应用程序时,该方法支持可伸缩性.
闽公网安备 35060202000074号