浏览 3472 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-08-31
Jetty Continuations 很好的解决了服务器更新客户端的问题,服务器不用再为每一个等待响应的客户端单独建立一个线程,借助Continuations和新IO,可以在有限的线程内支持更多用户。 更多内容参见http://docs.codehaus.org/display/JETTY/Continuations 最近在做一个浏览器上的在线聊天项目,用来做为在线客服支持,打算使用GWT编写界面,但是GWT所提供RPC机制并不直接支持Jetty Continuations。为了支持比当前线程数更多的用户,Jetty中的Continuation.suspend()会抛出一个特殊的运行时异常:RetryRequest。这个异常将传播到servlet以外,然后通过过滤器传回,再由SelectChannelConnector捕获,将请求放入处于等待状态的Continuation队列中,此时HTTP连接并不关闭,而当前的线程却可以被放回线程池,供别的请求使用。但是使用GWT时,GWT捕获了所有的Throwable,这样就会导致Continuations机制失败。而且GWT提供的RemoteServiceServlet类中很多方法都被定义为final或static,于是你无法通过继承这个类来重写相关方法,让它放过RetryRequest。 但是因为GWT是开源项目,于是Jetty组织改写RemoteServiceServlet,提供了OpenRemoteServiceServlet,将Continuations所敏感的方法去掉final和static,然后继承OpenRemoteServiceServlet,提供了它们自己的AsyncRemoteServiceServlet,这样我们GWT服务器端的RPC接口的实现类直接继承AsyncRemoteServiceServlet,无须其它更改,就可以使用Jetty Continuations的API了。 AsyncRemoteServiceServlet14.java中放过RetryRequest的相关代码: /** * Throws the Jetty RetryRequest if found. * * @param caught the exception */ protected void throwIfRetyRequest(Throwable caught) { if (caught instanceof UnexpectedException) { caught = caught.getCause(); } if (caught instanceof RuntimeException && JETTY_RETRY_REQUEST_EXCEPTION.equals(caught.getClass().getName())) { throw (RuntimeException) caught; } } 更多内容参见http://blogs.webtide.com/gregw/2006/12/07/1165517549286.html 这里提供一个完整的小例子给大家,也作为我这段时间学习的总结 : 下载最新的 GWT http://code.google.com/webtoolkit/download.html Jetty http://docs.codehaus.org/display/JETTY/Downloading+and+Installing#download 然后在http://jira.codehaus.org/browse/JETTY-399上面找到OpenRemoteServiceServlet14.java和AsyncRemoteServiceServlet14.java,这是OpenRemoteServiceServlet和AsyncRemoteServiceServlet的新版本,支持GWT1.4版本。 首先使用GWT的命令行工具创建eclipse下的GWT项目,然后导入到eclipse中,再导入jetty-util-6.1.3.jar。 RPC接口定义: public interface TestService extends RemoteService { public String getNews(); } GWT的入口类: public class GCEntry implements EntryPoint { public void onModuleLoad() { final TestServiceAsync testService = (TestServiceAsync)GWT.create(TestService.class); ServiceDefTarget target = (ServiceDefTarget)testService; target.setServiceEntryPoint(GWT.getModuleBaseURL() + "test"); final TextArea printArea = new TextArea(); printArea.setVisibleLines(10); printArea.setCharacterWidth(30); testService.getNews(new AsyncCallback() { public void onFailure(Throwable caught) { } public void onSuccess(Object result) { printArea.setText(printArea.getText() + result); testService.getNews(this); } }); DockPanel dp = new DockPanel(); dp.add(printArea, DockPanel.CENTER); RootPanel.get().add(dp); } } 界面将显示一个文本框,反复调用testService.getNews(),将异步返回的结果输出到文本框中。 服务器端RPC接口的实现: public class TestServiceImpl extends AsyncRemoteServiceServlet14 implements TestService { private NewsCreator newsCreator; public void init() { newsCreator = new NewsCreator(); } public String getNews() { return newsCreator.getNews(getThreadLocalRequest()); } } 注意这里继承的是AsyncRemoteServiceServlet14。通过一个辅助类NewsCreator来生成新的时间: public class NewsCreator implements Runnable { private Set<Continuation> readers; public NewsCreator() { readers = new HashSet<Continuation>(); new Thread(this).start(); } public void run() { while (true) { synchronized(this) { for (Continuation continuation : readers) { continuation.setObject(new Date().toString() + "\r\n"); continuation.resume(); } readers.clear(); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public String getNews(HttpServletRequest request) { Continuation continuation = ContinuationSupport.getContinuation(request, null); synchronized(this) { readers.add(continuation); } continuation.suspend(10000); String news = continuation.getObject() == null ? "No Time" : (String)continuation.getObject(); continuation.setObject(null); return news; } } getNews()为每个请求获取一个Continuation实例,然后将这个实例保存起来,阻塞10秒,同时NewsCreator每隔两秒发布一次时间,发布时将当前时间附在Continuation上,恢复被阻塞的Continuation。Continuation在被恢复或超时之后相对应的请求都会被重新执行,当再次执行到Continuation.suspend()时,这个方法会马上返回,然后继续执行suspend()后面的代码,返回上一次发布的时间或是"No Time",当然这里发布的间隔比阻塞的时间小,不会出现"No Time"。 完整代码见附件 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |