|
server端向?yàn)g覽器client發(fā)送通知這種通訊模式在J2EE應(yīng)用中很常見(jiàn),通常使用采用RMI、CORBA或者自定義TCP/IP信息的applet來(lái)實(shí)現(xiàn)。這些技術(shù)往往由于復(fù)雜而產(chǎn)生諸多不利之處:技術(shù)難以實(shí)現(xiàn)、存在防火墻限制(因?yàn)樾枰蜷_(kāi)非HTTP的通訊端口)、需要額外的server開(kāi)發(fā)和維護(hù)。并且除了刷新整個(gè)頁(yè)面或者完全采用applet展示內(nèi)容之外,很難找到別的方法...
作者:cleverpig ![]() 介紹 server端向?yàn)g覽器client發(fā)送通知這種通訊模式在J2EE應(yīng)用中很常見(jiàn),通常使用采用RMI、CORBA或者自定義TCP/IP信息的applet來(lái)實(shí)現(xiàn)。這些技術(shù)往往由于復(fù)雜而產(chǎn)生諸多不利之處:技術(shù)難以實(shí)現(xiàn)、存在防火墻限制(因?yàn)樾枰蜷_(kāi)非HTTP的通訊端口)、需要額外的server開(kāi)發(fā)和維護(hù)。并且除了刷新整個(gè)頁(yè)面或者完全采用applet展示內(nèi)容之外,很難找到別的方法將client端applet的狀態(tài)和瀏覽器的頁(yè)面內(nèi)容集成在一起。 Pushlet是一種comet實(shí)現(xiàn):在Servlet機(jī)制下,數(shù)據(jù)從server端的Java對(duì)象直接推送(push)到(動(dòng)態(tài))HTML頁(yè)面,而無(wú)需任何Java applet或者插件的幫助。它使server端可以周期性地更新client的web頁(yè)面,這與傳統(tǒng)的request/response方式相悖。瀏覽器client為兼容JavaScript1.4版本以上的瀏覽器(如Internet Explorer、FireFox),并使用JavaScript/Dynamic HTML特性。而低層實(shí)現(xiàn)使用一個(gè)servlet通過(guò)Http連接到JavaScript所在的瀏覽器,并將數(shù)據(jù)推送到后者。有關(guān)JavaScript版本的知識(shí)請(qǐng)參看Mozilla開(kāi)發(fā)中心提供的《JavaScript核心參考》和Stephen Chapman編寫的《What Version of Javascript》。 這種機(jī)制是輕量級(jí)的,它使用server端的servlet連接管理、線程工具、javax.servlet API,并通過(guò)標(biāo)準(zhǔn)Java特性中Object的wait()和notify()實(shí)現(xiàn)的生產(chǎn)者/消費(fèi)者機(jī)制。原則上,Pushlet框架能夠運(yùn)行在任何支持servlet的server上、防火墻的后面。當(dāng)在client中使用JavaScript/DHTML時(shí),Pushlet提供了通過(guò)腳本快速建立應(yīng)用、使用HTML/CSS特性集成和布局新內(nèi)容的便利方法。 動(dòng)機(jī) 目前越來(lái)越多的servlet和JSP用來(lái)部署web,于是便出現(xiàn)了在頁(yè)面已經(jīng)裝載完畢后由于server端某些對(duì)象的狀態(tài)變化而產(chǎn)生對(duì)client瀏覽器進(jìn)行通知和同步的需要。 這些狀態(tài)變化的原因很復(fù)雜:可能由于用戶通過(guò)訪問(wèn)servlet或者修改數(shù)據(jù)庫(kù)記錄、更新EJB造成,或是在多用戶應(yīng)用(比如聊天室和共享白板)中的事件導(dǎo)致數(shù)據(jù)狀態(tài)變化。這些類型的應(yīng)用常常使用一種分布式的MVC模板:模式層位于server上(可能緩存在client中),控制層和視圖層位于client中(這兩個(gè)層可能合為一體)。 當(dāng)然,這里也存在需要訂閱server端動(dòng)態(tài)內(nèi)容的應(yīng)用:那些動(dòng)態(tài)內(nèi)容不停地從server端推送過(guò)來(lái)。例如股票實(shí)時(shí)情報(bào)、系統(tǒng)狀態(tài)報(bào)告、天氣情況或者其它的監(jiān)測(cè)應(yīng)用。它遵循觀察者(Observer)模板(也稱為發(fā)布/訂閱模板),這種模板中的遠(yuǎn)程client注冊(cè)成為關(guān)注于server端對(duì)象變化的觀察者。關(guān)于設(shè)計(jì)模板的知識(shí)請(qǐng)看Matrix Wiki上的介紹。 那么在HTML頁(yè)面已經(jīng)被裝載后如何通知瀏覽器客戶端?或者如果有選擇地更新頁(yè)面中一些部分的話,那該怎么做?比如只更新在HTML Table中的那些價(jià)格發(fā)生變化的股票列? 多種通知解決方案 讓我們對(duì)應(yīng)用進(jìn)行這樣的假設(shè):擁有一個(gè)Java web server或者Java應(yīng)用server,我們?cè)噲D從server發(fā)送通知給client端瀏覽器。這里的解決方案可以分為:“輪詢(polling)”、“服務(wù)端回調(diào)(server-side callbacks)”和“消息(messaging)”三類。 輪詢 最簡(jiǎn)單的解決方案便是“定時(shí)刷新頁(yè)面”。在HTML文檔的頭部使用HTML META標(biāo)簽,頁(yè)面便可以每隔N秒自動(dòng)reload一次。如果在此期間server端數(shù)據(jù)發(fā)生變化,那么我們可以獲得新的內(nèi)容,否則將得到相同的頁(yè)面。雖然方法很簡(jiǎn)單,但是如何設(shè)置刷新間隔是讓人頭疼的大問(wèn)題。 服務(wù)端回調(diào) 因?yàn)槲覀兪恰吧斫?jīng)百戰(zhàn)”的Java開(kāi)發(fā)老手,所以經(jīng)常會(huì)用到“服務(wù)端回調(diào)”。這種方式通過(guò)RMI或者CORBA將Server端的對(duì)象傳輸?shù)絁ava applet客戶端。 消息(MOM) 這種解決方案采用一個(gè)作為client的applet,它使用TCP/IP或者無(wú)連接的UDP、甚至多播協(xié)議來(lái)建立與消息中間鍵server的通訊,然后由server推送消息給client。你可以從例如SoftWired的iBus、IBM的MQSeries、BEA的WebLogic Event這些消息產(chǎn)品中直接挑選,或者自己使用基于socket的java.io.ObjectStream定制開(kāi)發(fā)消息軟件。 討論(MOM) 上面三種解決方案在復(fù)雜性、安全性、性能、可測(cè)量性、瀏覽器兼容性、防火墻限制上各有優(yōu)勢(shì)、劣勢(shì)。最佳解決方案依賴于你的應(yīng)用需求。例如,在共享白板應(yīng)用中,用戶需要直接與“狀態(tài)”交互,那么server端回調(diào)或者消息很可能會(huì)大顯身手。 但在瀏覽器環(huán)境下,除非完全使用applet作為整個(gè)client應(yīng)用,否則把來(lái)自于server的更新信息集成到頁(yè)面中并非易事。如何在applet收到回調(diào)或者消息時(shí)變更頁(yè)面相關(guān)內(nèi)容?一個(gè)很“痛快”而又“痛苦”的解決方案就是在回調(diào)方法中使用AppletContext.showDocument(URL)方法來(lái)刷新整個(gè)頁(yè)面。 由于HTML代碼可以直接影響頁(yè)面布局,直接使用來(lái)自server的數(shù)據(jù)更改HTML部分內(nèi)容不是更好嗎?這是web應(yīng)用的理想方案,在server上內(nèi)容動(dòng)態(tài)改變時(shí),從用戶到server所需的交互是最小化的。作為對(duì)上面的解決方案的補(bǔ)充,我開(kāi)發(fā)了Pushlet這種輕量級(jí)、瘦客戶端的技術(shù),它無(wú)需applet或者插件而直接與腳本/HTML集成在一起、使用標(biāo)準(zhǔn)HTTP連接、理論上可以部署到任何支持Java servlet的server上。但這并不意味著它將替換對(duì)前面解決方案,而是在你的開(kāi)發(fā)“工具箱”中添加另一種選擇。作為Java構(gòu)架者/開(kāi)發(fā)者,你可以自行權(quán)衡、選擇、決定哪種適合應(yīng)用的解決方案。 Pushlet原理 Pushlet的基本使用形式是極為簡(jiǎn)單的。后面的一些示例會(huì)說(shuō)明這一點(diǎn)。 HTTP流 ![]() 極富生活韻味的“Urban Stream”把我們Connecting Together Pushlet基于HTTP流,這種技術(shù)常常用在多媒體視頻、通訊應(yīng)用中,比如QuickTime。與裝載HTTP頁(yè)面之后馬上關(guān)閉HTTP連接的做法相反,Pushlet采用HTTP流方式將新數(shù)據(jù)源源不斷地推送到client,再此期間HTTP連接一直保持打開(kāi)。有關(guān)如何在Java中實(shí)現(xiàn)這種Keep-alive的長(zhǎng)連接請(qǐng)參看Sun提供的《HTTP Persistent Connection》和W3C的《HTTP1.1規(guī)范》。 示例1 我們利用HTTP流開(kāi)發(fā)一個(gè)JSP頁(yè)面(因?yàn)樗子诓渴穑宜趙eb server中也是作為servlet對(duì)待的),此頁(yè)面在一個(gè)定時(shí)器循環(huán)中不斷地發(fā)送新的HTML內(nèi)容給client:
在Pushlet源代碼中提供了此頁(yè)面(examples/basics/push-html-stream.jsp)。上面的頁(yè)面并不是十分有用,因?yàn)樵谖覀兯⑿马?yè)面時(shí),新內(nèi)容機(jī)械地、持續(xù)不斷地被添加到頁(yè)面中,而不是server端更新的內(nèi)容。 示例2 現(xiàn)在讓我們步入Pushlet工作機(jī)理中一探究竟。通過(guò)運(yùn)行Pushlet的示例源代碼(examples/basics/ push-js-stream.html),我們會(huì)看到這個(gè)每3秒刷新一次的頁(yè)面。那么它是如何實(shí)現(xiàn)的呢? 此示例中包含了三個(gè)文件:push-js-stream.html、push-js-stream-pusher.jsp、push-js-stream-display.html。 其中push-js-stream.html是主框架文件,它以HTML Frame的形式包含其它兩個(gè)頁(yè)面。 push-js-stream-pusher.jsp是一個(gè)JSP,它執(zhí)行在server端,此文件內(nèi)容如下:
注意在示例1和示例2中使用JSP時(shí)都存在一個(gè)問(wèn)題:一些servlet引擎在某個(gè)client離開(kāi)時(shí)會(huì)“吃掉”IOException,以至于JSP頁(yè)面將永不拋出此異常。所以在這種情況下,頁(yè)面循環(huán)將會(huì)永遠(yuǎn)執(zhí)行下去。而這正是Pushlet實(shí)現(xiàn)采用servlet的原因之一:可以捕獲到IOException。 在上面代碼的第21行中可以看到在一個(gè)定時(shí)器循環(huán)(3秒/周期)中打印了一些HTML并將它們輸出到client瀏覽器。請(qǐng)注意,這里推送的并非HTML而是Javascript!這樣做的意義何在? 它把類似“<script language=JavaScript >parent.push(‘Page 4‘)</script>”的一行代碼推送到瀏覽器;而具有JavaScript引擎的瀏覽器可以直接執(zhí)行收到的每一行代碼,并調(diào)用parent.push()函數(shù)。而代碼中的Parent便是瀏覽器頁(yè)面中所在Frame的Parent,也就是push-js-stream.html。讓我們看看都發(fā)生了什么?
可以看到push-js-stream.html中的push()函數(shù)被名為pushletFrame的JSP Frame調(diào)用:把傳入的參數(shù)值寫入到displayFrame(此Frame為push-js-stream-display.html)。這是動(dòng)態(tài)HTML的一個(gè)小技巧:使用document對(duì)象的writeln方法刷新某個(gè)Frame或者Window的內(nèi)容。 于是displayFrame成為了用于顯示內(nèi)容的、真正的視圖。displayFrame初始化為黑色背景并顯示“wait…”直到來(lái)自server的內(nèi)容被推送過(guò)來(lái):
這便是Pushlet的基本做法:我們從servlet(或者從示例中的JSP)把JavaScript代碼作為HTTP流推送到瀏覽器。這些代碼被瀏覽器的JavaScript引擎解釋并完成一些有趣的工作。于是便輕松地完成了從server端的Java到瀏覽器中的JavaScript的回調(diào)。 上面的示例展示了Pushlet原理,但這里存在一些等待解決的問(wèn)題和需要增添的特性。于是我建立了一個(gè)小型的server端Pushlet框架(其類結(jié)構(gòu)圖表將會(huì)展示在下面),添加了一些用在client中的JavaScript庫(kù)。由于client需要依賴更多的DHTML特性(比如Layers),我們將首先粗略地溫習(xí)一些DHTML知識(shí)。示例代碼見(jiàn)examples/dhtml。 DHTML(動(dòng)態(tài)HTML) DHTML(動(dòng)態(tài)HTML)提供了在瀏覽器中維護(hù)內(nèi)容、進(jìn)行用戶交互的擴(kuò)展能力。就像Java開(kāi)發(fā)者使用servlet和JSP那樣,DHTML也應(yīng)該是你的工具箱中的一部分。 DHTML涉及到HTML、級(jí)聯(lián)樣式表(CSS)、JavaScript和DOM。傳統(tǒng)的頁(yè)面只能通過(guò)重新裝載來(lái)自server新頁(yè)面的方式進(jìn)行更新。DHTML提供了在頁(yè)面被裝載完畢后對(duì)瀏覽器內(nèi)的HTML文檔的完全控制。你應(yīng)該見(jiàn)過(guò)一些帶有“圖像翻滾”、彈出內(nèi)容、可收縮菜單功能的web頁(yè)面,它們便是使用DHTML技術(shù)實(shí)現(xiàn)的。盡管存在一些標(biāo)準(zhǔn)上的差異(見(jiàn)下面的“跨瀏覽器DHTML”),多數(shù)兼容JavaScript1.4版本的瀏覽器(后面將簡(jiǎn)稱為“版本4的瀏覽器”)都支持DHTML。 從開(kāi)發(fā)者的角度審視瀏覽器中的整個(gè)文檔,比如Frame、圖片、表格等,它們都可以表示為具有層次的對(duì)象模式——DOM。通過(guò)使用JavaScript可以維護(hù)DOM的成員,不但可以改變文檔的內(nèi)容和外觀,而且還可以捕捉例如鼠標(biāo)移動(dòng)、form提交這些用戶事件,而后對(duì)DOM進(jìn)行相應(yīng)修改。例如鼠標(biāo)移動(dòng)到圖片的上方可以產(chǎn)生“mouse-over”事件,這時(shí)通過(guò)顯示高亮版本的圖片或者彈出解釋性文字的方式修改頁(yè)面外觀。這聽(tīng)起來(lái)不錯(cuò)吧!我們現(xiàn)在就熟悉一下DHTML標(biāo)準(zhǔn)!但是誰(shuí)定義了DHTML標(biāo)準(zhǔn)? 這是一些DHTML初學(xué)者首先遇到的問(wèn)題。首先,你需要一個(gè)版本4以上的瀏覽器。DHTML相關(guān)規(guī)范的官方標(biāo)準(zhǔn)出自World Wide Web Consortium (W3)。但是微軟和Netscape出品的版本4以上的瀏覽器都有一些私有的DHTML擴(kuò)展,這是你必須注意的。 幸運(yùn)的是大多數(shù)用戶都有版本4以上的瀏覽器,而且一些開(kāi)發(fā)者(Dannymen、Dan Steinman和Danny Goodman)建造了跨越瀏覽器的、可重用的DHTML庫(kù)。 作為一名Java開(kāi)發(fā)者,你要接受這個(gè)事實(shí):你應(yīng)該適當(dāng)?shù)孛靼谆趯?duì)象、甚至面向?qū)ο蟮腏avaScript編程。在我的DHTML中你將找到一些示例,但了解更多的DHTML資源也是很值得的。尤其在使用跨越瀏覽器的DHTML庫(kù)對(duì)付那些頑固的瀏覽器問(wèn)題時(shí),一切都變得有趣、而不是枯燥。 就如Java獲得在廣闊的server端市場(chǎng)、DHTML在client領(lǐng)域具有許多強(qiáng)大特性那樣,Pushlet以一種直接的方式將這兩項(xiàng)偉大的技術(shù)捆綁在一起。下一個(gè)章節(jié)將詳細(xì)討論P(yáng)ushlet這個(gè)server端輕量級(jí)框架和client端DHTML庫(kù)。 框架的設(shè)計(jì) 注意:本章節(jié)僅反映了Pushlet server端框架的1.0版本(隨著版本升級(jí)可能還會(huì)重新構(gòu)造)。 Pushlet框架允許client訂閱在server端的主題(subject),而server則接收訂閱,然后在server端的訂閱主題所對(duì)應(yīng)的數(shù)據(jù)變化時(shí)推送數(shù)據(jù)到client。此框架的基本設(shè)計(jì)模板是發(fā)布/訂閱(Publish/Subscrib),也被稱為觀察者(Observer)。它具有server和client兩部分組建而成: Server端: 由圍繞著Pushlet類的Java類集合構(gòu)成(見(jiàn)下面的UML類設(shè)計(jì)圖表)。 Client端: 腳本與頁(yè)面:可重用的JavaScript庫(kù)(pushlet.js)和用來(lái)在DHTML client(這里指瀏覽器)中接收事件的HTML(pushlet.html)組成。 Client端Java類: JavaPushletClient.java和JavaPushletClientListener.java,負(fù)責(zé)在Java client中接收事件。 跨越瀏覽器的DHTML工具庫(kù): layer.js, layer-grid.js, layer-region.js,用來(lái)在DHTML層中顯示數(shù)據(jù)內(nèi)容。 最后,還有用于測(cè)試事件的生成工具類EventGenerators.java以及一些示例應(yīng)用。 server端類設(shè)計(jì) 下面是server端Java類的UML圖表: ![]() Pushlet框架Java類UML圖 關(guān)鍵的類:Pushlet、Publisher類、Subscriber接口和Event類。通過(guò)HTTP請(qǐng)求調(diào)用Pushlet這個(gè)servlet,client訂閱事件并接收事件。 Client發(fā)送訂閱請(qǐng)求時(shí)需要表明的內(nèi)容如下: 1.訂閱事件的主題 2.接收事件所采用的格式:默認(rèn)為JavaScript調(diào)用,還有XML或者Java序列化對(duì)象者三種。目前Pushlet 2.0.2版已經(jīng)支持AJAX。 3.使用哪種接收協(xié)議(將來(lái)實(shí)現(xiàn)):TCP/IP、UDP、Multicast。 示例:用于接收AEX股票價(jià)格的請(qǐng)求,默認(rèn)使用JavaScript調(diào)用作為格式。
主題(subject)表示為具有層次的“主題樹(shù)”(topic-tree)形式。例如:“/stocks”表示與股票價(jià)格相關(guān)的所有事件,而“/stocks/aex”表示Amsterdam Exchange公司的股票價(jià)格?!?”表示所有事件。這并不時(shí)硬性規(guī)定,而是由開(kāi)發(fā)者根據(jù)應(yīng)用自行定義。 當(dāng)前只有接收方協(xié)議是發(fā)送到client的HTTP回應(yīng)流(response stream)。在將來(lái)的擴(kuò)展版本中,接收方協(xié)議能夠提供多種選擇,比如TCP、UDP、RMI、HTTP POST甚至只SMTP。 Event(事件)類:僅僅是name/value的字符串對(duì)(使用java.util.Properties實(shí)現(xiàn))的集合。 產(chǎn)生Event的方式:Publisher類為生成的Event提供了發(fā)布接口,它內(nèi)部保存了訂閱者(那些實(shí)現(xiàn)Subscriber接口的類)列表,并把每個(gè)Event發(fā)送給那些主題與Event匹配的訂閱者。Event在server端也可以通過(guò)能夠偵聽(tīng)外部Event的EventGenerators類來(lái)生成。另外client可以通過(guò)基于HTTP通訊的Postlet類來(lái)發(fā)布Event。 在上面的圖表中,為了適配不同請(qǐng)求源(瀏覽器、Java client程序),PushletSubscriber以及它所包含的那些類提供了多種訂閱者的實(shí)現(xiàn)。 場(chǎng)景1: 事件訂閱 ![]() 瀏覽器client訂閱程序圖 上面的UML程序圖中,瀏覽器client通過(guò)Publisher訂閱Event。 Pushlet作為servlet,通過(guò)doGet/doPost方法被調(diào)用。由于多個(gè)client可以同時(shí)調(diào)用同一個(gè)Pushlet,所以Pushlet本身不能作為訂閱者。取而代之的是,它派發(fā)所有的訂閱:在每一次調(diào)用doGet()/doPost()時(shí),新建PushletSubscriber對(duì)象、并使之運(yùn)行直至事件循環(huán)(eventLoop)結(jié)束。PushletSubscriber作為一個(gè)實(shí)現(xiàn)Subscriber接口的對(duì)象,通過(guò)join()方法向Publisher類進(jìn)行注冊(cè)的方式將自身添加到Publisher的內(nèi)部列表。 面對(duì)不同的client類型和協(xié)議,PushletSubscriber建立一個(gè)相對(duì)的ClientAdapter對(duì)象,在這個(gè)場(chǎng)景中是BrowserPushletAdapter對(duì)象。而對(duì)于支持Multipart MIME的瀏覽器,將建立MultipartBrowserClientAdapter對(duì)象。 最后的deQueue()調(diào)用是一個(gè)“等待Event的循環(huán)”,deQueue的意思為入隊(duì)。注意此方法將掛起當(dāng)前線程直到PushletSubscriber的GuardedQueue隊(duì)列中存入有效的Event。 場(chǎng)景2: 發(fā)送和派發(fā)事件 ![]() 事件發(fā)布程序圖 上圖顯示了發(fā)送一個(gè)事件所要經(jīng)歷的程序。它展現(xiàn)了Event如何被生成、被派發(fā)給瀏覽器client。在這個(gè)場(chǎng)景中,EventGenerator建立了一個(gè)Event對(duì)象,并調(diào)用Publisher.publish()將其派發(fā)到client。Publisher遍歷它內(nèi)部的訂閱者列表,詢問(wèn)這個(gè)Event是否匹配訂閱標(biāo)準(zhǔn)(目前只是主題匹配)。如果發(fā)現(xiàn)與之匹配的訂閱者,則調(diào)用該訂閱者的send()方法。 每個(gè)PushletSubscriber對(duì)象都有一個(gè)GuardedQueue對(duì)象,在其中以隊(duì)列的形式保存著調(diào)用send()方法時(shí)傳入的Event。那么它為什么不直接將Event推送給BrowserPushletAdapter呢?最重要的原因是我們期望掛起B(yǎng)rowserPushletAdapter線程,直到GuardedQueue中存在有效的Event,這樣就避免了“忙于等待”或者“輪詢”方式所帶來(lái)的負(fù)面影響。第二原因是Publisher可以通知多個(gè)client,如果在執(zhí)行同步的send()調(diào)用時(shí),某個(gè)慢速的client可能會(huì)堵塞所有其它正在等待通知的client。這正是我在RMI或者CORBA提供的一組client進(jìn)行同步回調(diào)的示例中所看到的設(shè)計(jì)缺陷。 GuardedQueue是個(gè)工具類,它使用了讀/寫模板(readers-writers pattern),此模板采取java.lang.Object.wait()/notifyAll()方法實(shí)現(xiàn)可被監(jiān)控的掛起。通過(guò)使用讀/寫模板,使GuardedQueue類具有進(jìn)行對(duì)象入隊(duì)/出隊(duì)(enqueue/dequeue)操作的能力。當(dāng)隊(duì)列為空時(shí),GuardedQueue調(diào)用deQueue()方法時(shí),此時(shí)調(diào)用線程將被掛起,直到有對(duì)象入隊(duì)為止。相反,當(dāng)隊(duì)列已滿時(shí)調(diào)用enQueue(),線程也將掛起。在BrowserPushletSubscriber獲得出隊(duì)的Event對(duì)象后,它將調(diào)用BrowserPushletAdapter的push()方法,后者將格式化Event為JavaScript代碼或者XML以及其它格式),并將它發(fā)送到瀏覽器。比如Philips股票價(jià)格為123.45的JavaScript代碼格式如下:
Client端框架 由于這是對(duì)于所有瀏覽器client的通用任務(wù),所以Pushlet Client端框架提供了兩個(gè)可重用的文件: pushlet.html和pushlet.js。 Pushlet.html本身是被附著在一個(gè)隱藏的HTML Frame中。這個(gè)Frame的parent調(diào)用并實(shí)現(xiàn)push()方法。 pushlet.html :被包含在client端的HTML文檔中的Frame中。它可以傳入主題標(biāo)識(shí)和背景顏色兩個(gè)參數(shù)。而它所做的最重要的工作是下面的push方法:
Push()函數(shù)首先根據(jù)傳入的參數(shù)建立了一個(gè)JavaScript對(duì)象——pushletEvent。接著使用updateStatusFrame()顯示閃光,表示我們正在接收Event數(shù)據(jù),如果parent frame存在onPush()函數(shù),則將前面建立的PushletEvent對(duì)象作為參數(shù)調(diào)用parent frame指定的處理方法。 在pushlet.js 中的PushletEvent類代碼如下:
PushletEvent使用了一個(gè)我增加的Map JavaScript對(duì)象,它類似于java.util.Hashtable。 Pushlet協(xié)議 詳見(jiàn)http://www./doc/protocol.html 應(yīng)用 Pushlet可以開(kāi)發(fā)多種類型的web應(yīng)用。由于此框架允許client主動(dòng)更新事件(通過(guò)Postlet),所以應(yīng)用就并不只是被動(dòng)地推送數(shù)據(jù)了。每個(gè)Pushlet應(yīng)用都可以根據(jù)下面進(jìn)行分類: 事件由server發(fā)起、還是client發(fā)起或者兩者都有可能;狀態(tài)是否保持在server、還是在client或者兩者都有可能。 由于事件不但被做成了對(duì)JavaScript有效,而且也是其它腳本化的插件能夠接收實(shí)時(shí)的事件更新。例如你可以腳本化Macromedia Flash或者VRML應(yīng)用。 為了說(shuō)明Pushlet應(yīng)用的范圍,下面提供了一些簡(jiǎn)單的demo。 監(jiān)控 例如股票、天氣、投票、機(jī)場(chǎng)到達(dá)系統(tǒng),這些應(yīng)用都可以采用Pushlet對(duì)實(shí)時(shí)數(shù)據(jù)進(jìn)行監(jiān)控。 這是一個(gè)實(shí)時(shí)FX股票/新聞應(yīng)用:www. (IE only). 另一個(gè)部署Pushlet的實(shí)時(shí)股票/新聞應(yīng)用:www.marketnews.com. 游戲 從象棋到描述危機(jī)和壟斷者的游戲。 分布式MVC 這涉及到了在用戶接口框架(例如Java Swing和微軟MFC)中常見(jiàn)的設(shè)計(jì)模板。在分布式MVC的各種變體中,模式層位于server,而client控制著是視圖層和控制層。Client通過(guò)控制進(jìn)而修改模式,然后模式將通知所有依附的視圖,而視圖將進(jìn)行自我刷新。 一些應(yīng)用具有web前端(front end),其數(shù)據(jù)存放在server上可被多個(gè)用戶更新。比如預(yù)訂系統(tǒng)和登記系統(tǒng)。如果一個(gè)client完成一次更新,而其它c(diǎn)lient卻不能馬上見(jiàn)到變化直至刷新頁(yè)面。在某些情況下,這是很簡(jiǎn)單、可行的解決方案,但同時(shí)也存在著用戶需要同步變化的情況。這種情況下,應(yīng)用可以使用Pushlet簡(jiǎn)單地將URL作為單一事件推送到client,client接收到這個(gè)URL后將刷新頁(yè)面。 另外一點(diǎn)值得注意的示例是爭(zhēng)議頗多的EJB。盡管Java client能夠直接和EJB對(duì)話(通過(guò)RMI或者CORBA),但多數(shù)情況下則是由servlet和作為client前端的JSP來(lái)完成。在這種情況下,“通知”工作變得很艱難。使用Pushlet,EJB可以在其狀態(tài)發(fā)生改變時(shí)通知依附于它的web client。 Web表示層 在放棄使用PowerPonit作Java課程講解工具后,我開(kāi)發(fā)了一個(gè)基于XML的內(nèi)容管理框架。由于在某些情形下,教室沒(méi)有“卷軸工”,但是所有的學(xué)生人手一臺(tái)網(wǎng)絡(luò)計(jì)算機(jī),所以我開(kāi)發(fā)了這個(gè)簡(jiǎn)單的應(yīng)用,它使我能夠同步改變學(xué)生和我的頁(yè)面內(nèi)容。 用戶輔助 這種類型的應(yīng)用可用于call center、銀行、幫助桌面、電子商務(wù)web應(yīng)用。當(dāng)你由于問(wèn)題而撥打call center電話時(shí),代理程序可以使你通過(guò)上網(wǎng)的方式瀏覽解決方案、供貨等信息。 使用EJB作為后臺(tái)和JSP作為前臺(tái),client可以買/賣外幣。一個(gè)“AutoTrader”對(duì)象自動(dòng)提供處理,如果自動(dòng)處理失敗或者client請(qǐng)求人工處理時(shí),一個(gè)“處理干預(yù)”將發(fā)生,處理者將被通知并提供相應(yīng)的服務(wù)。 社區(qū)工具 這是一種多用戶參加實(shí)時(shí)會(huì)話的應(yīng)用。我正在計(jì)劃擴(kuò)充Pushlet框架,使其支持多用戶session的特性。目前可以實(shí)現(xiàn)簡(jiǎn)單的web聊天,我稱之為WCQ,大家可以在Pushlet源代碼的example中見(jiàn)到它。 比較 本章節(jié)對(duì)Pushlet與基于CORBA/RMI的Java applet解決方案進(jìn)行一下比較。 優(yōu)勢(shì) 直接與瀏覽器中的DHTML集成。 標(biāo)準(zhǔn)的HTTP端口和協(xié)議:消息和RMI/CORBA使用非標(biāo)準(zhǔn)端口(相對(duì)HTTP標(biāo)準(zhǔn)端口而言),遇到“防火墻”、“禁止回調(diào)”、“禁止接收UDP數(shù)據(jù)”的瀏覽器安全限制時(shí)可能無(wú)法工作。 client負(fù)載:基于CORBA/RMI的Java applet使client在啟動(dòng)時(shí)更加沉重,并消耗更多的資源。 無(wú)需額外的server:消息和RMI/CORBA需要單獨(dú)的server產(chǎn)品。Pushlet理論上可以在任何server引擎上運(yùn)行,并具備連接管理和多線程能力。 缺點(diǎn) 跨越瀏覽器的DHTML:Pushlet需要使用能工作在任何平臺(tái)、所有瀏覽器版本的DHTML庫(kù)。 可測(cè)量性:當(dāng)100個(gè)以上的client通過(guò)Pushlet連接到server時(shí),server上的線程和socket資源都將出現(xiàn)緊張。而解決這一問(wèn)題的方式就是使用單獨(dú)的Pushlet服務(wù)器。 Web server問(wèn)題:一般的web server往往不是為長(zhǎng)連接而設(shè)計(jì)的。針對(duì)這一問(wèn)題的解決方案與上面的可測(cè)量性相同。 代理緩存:一些代理服務(wù)器可能緩存HTTP數(shù)據(jù)。 |
|
|