2009-03-06 62 views
6

有沒有什麼辦法從GWT「訂閱」到JSON對象流,並在保持活動連接上偵聽傳入事件,而不嘗試一次全部獲取它們?我相信這項技術的流行詞是「彗星」。GWT/Comet:任何經驗?

讓我們假設我有打開保持活動連接HTTP服務,並把JSON與傳入股票報價對象有實時:

{"symbol": "AAPL", "bid": "88.84", "ask":"88.86"}
{"symbol": "AAPL", "bid": "88.85", "ask":"88.87"}
{"symbol": "IBM", "bid": "87.48", "ask":"87.49"}
{"symbol": "GOOG", "bid": "305.64", "ask":"305.67"}
...

我需要聽取這些事件並實時更新GWT組件(表格,標籤)。任何想法如何做到這一點?

回答

6

有一個GWT彗星模塊StreamHub:

http://code.google.com/p/gwt-comet-streamhub/

StreamHub是一個免費的社區版彗星服務器。有一個例子在行動here

你需要下載StreamHub彗星服務器並創建一個新的SubscriptionListener,使用StockDemo例子作爲起點,然後創建一個新的JsonPayload到流中的數據:

Payload payload = new JsonPayload("AAPL"); 
payload.addField("bid", "88.84"); 
payload.addField("ask", "88.86"); 
server.publish("AAPL", payload); 
... 

從下載JAR谷歌的代碼的網站,將其添加到您的GWT項目類路徑,並添加包括你的GWT模塊:

<inherits name="com.google.gwt.json.JSON" /> 
<inherits name="com.streamhub.StreamHubGWTAdapter" /> 

連接,並從你的GWT代碼訂閱:

StreamHubGWTAdapter streamhub = new StreamHubGWTAdapter(); 
streamhub.connect("http://localhost:7979/"); 
StreamHubGWTUpdateListener listener = new StockListener(); 
streamhub.subscribe("AAPL", listener); 
streamhub.subscribe("IBM", listener); 
streamhub.subscribe("GOOG", listener); 
... 

然後處理您在更新監聽器(也是在GWT代碼)怎麼樣更新:

public class StockListener implements StreamHubGWTUpdateListener { 
     public void onUpdate(String topic, JSONObject update) { 
      String bid = ((JSONString)update.get("bid")).stringValue(); 
      String ask = ((JSONString)update.get("ask")).stringValue(); 
      String symbol = topic; 
      ... 
     } 
} 

不要忘記在你的GWT項目主HTML頁面streamhub-min.js。

1

GWT的Comet實現的一些初步想法可以在here...找到,但我不知道是否有更成熟的東西。

1

另外,GWT/Comet集成的一些見解可用there,使用更多切割和邊緣技術:「Jetty Continuations」。值得一看。

5

我已經在一些項目中使用了這種技術,儘管它確實存在問題。我應該注意到,我只是通過GWT-RPC來完成這個工作,但是對於你用來處理數據的任何機制,原理都是一樣的。根據你在做什麼,可能沒有太多需要過度複雜的事情。

首先,在客戶端,我不相信GWT可以正確支持任何類型的流數據。在客戶端實際處理數據之前連接必須關閉。這意味着從服務器推送的角度來看,您的客戶端將連接到服務器並阻塞,直到數據可用時它將返回。無論在完成的連接上執行哪些代碼,都應立即重新打開與服務器的新連接以等待更多數據。

從服務器端的東西,你只需放入一個等待週期(java併發包特別方便與塊和超時),直到新的數據可用。在那個時候,服務器可以將一個數據包返回給客戶端,客戶端會相應地進行更新。根據數據流的類型,有一系列的考慮因素,但這裏有幾點需要考慮:

  • 客戶端是否獲得每一個更新都很重要?如果是這樣,那麼服務器需要在客戶端獲取某些數據並重新連接之間緩存任何潛在事件。
  • 是否有更新的空白?如果是這種情況,那麼打包大量更新並在每隔幾秒鐘的時間將數據塊按下一次可能更明智一些,而不是讓客戶端一次獲得一個更新。
  • 服務器可能需要一種方法來檢測客戶端是否已經離開,以避免爲該客戶端堆積大量緩存的包。

我發現服務器推送方式存在兩個問題。有了大量的客戶端,這意味着Web服務器上的許多開放連接。根據所討論的Web服務器的不同,這可能意味着很多線程被創建並保持打開狀態。第二個與每個域的2個請求的典型瀏覽器限制有關。如果您能夠爲來自二級域的圖像,css和其他靜態內容提供服務,則可以緩解此問題。

+0

+1優秀的文章,一些偉大的見解。 – Federer 2010-04-06 08:16:40

+0

+1這正是我如何做到的。在Servlet 3.0規範中,「多線程」問題的解決方案拼寫爲「可掛起的請求」。 Jetty在7.0中對此提供了早期支持。 Tomcat稱之爲別的東西。 – 2010-08-22 21:34:48

0

Here您可以在IBM WebSphere Application Server上找到如何執行此操作的說明(附帶一些源代碼示例)。 Jetty或任何其他支持Comet的J2EE服務器應該不會太差。簡而言之,這個想法是:通過GWT RPC將您的Java對象編碼爲JSON字符串,然後使用cometd將其發送到客戶端,由Dojo接收它,從而觸發您的JSNI代碼,該代碼調用您的窗口小部件方法,將對象反序列化再次使用GWT RPC。瞧! :)

我對這個設置的經驗是積極的,除安全問題外,沒有任何問題。在這種情況下,如何實現彗星安全性並不明確......似乎Comet更新servlet應該具有不同的URL,然後才能應用J2EE安全性。

0

JBoss Errai項目有一個消息總線,它提供了雙向消息傳遞,爲cometd提供了一個很好的選擇。

0

我們對GWT應用中的ServerPush/Comet使用Atmosphere Framewrok(http://async-io.org/)。

在客戶端,框架具有非常簡單的GWT集成。在服務器端,它使用普通的Servlet。

我們目前正在生產中使用它,並且在集羣環境中擁有超過1000個concurent用戶。我們在修改Atmosphere源代碼的過程中遇到了一些問題。另外文檔非常薄。

框架是免費使用的。