Wicket1.3中Class熱加載--使用篇
Wicket是Apache網站下面的一個頂級項目,是類似于ASP.Net的Web開發框架,受到很多開發者的好評。其最新的正式版本是1.3.5,正在開發的版本是1.4。
1.3x版本系列是Wicket框架真正走向成熟的標志版本,在該版本中提供了Stateless頁面和控件,以及DiskPageStore支持文件存取,以避免大量Stateful控件占用過多內存引致OOM,而這一直是Wicket框架被人攻擊的關鍵點。另外對于開發人員來說,特別值得一提的則是它在1.3版本中支持了更好的Class熱加載。
其實J2EE開發人員都知道在J2EE應用程序的開發中,最麻煩的往往是調試。雖然JDK已經對類的熱加載提供了很好支持,當JVM以調試模式啟動的時候,可以在更改代碼以后,立即看到改動后的效果,但是代碼的修改往往只限于方法的實現,如果在類中添加戜刪除了一個Field或者是一個Method(該操作等于修改了類的簽名),那么JDK的熱加載就無法正常生效。雖然大部分的J2EE應用服務器(如Tomcat,WebLogic)都聲稱自己提供了Hot Deploy功能,當檢測到類文件被更新以后,可以重新加載相應的Web應用。但對于大部分的開發人員來說,這種Hot Deploy功能更象是一個雞肋,看不出什么實際價值。比如說如果在Session中放置了不支持序列化的對象,或者做了動態類增強,那么所謂的Hot Deploy幾乎是百分百出錯。以Tapestry3.04版本為例(它使用了CGLib做類增強),在Tomcat5和WebLogic10環境上(其它版本應該也是相同的,但沒有進行過測試),沒有一次能夠正確的Hot Deploy。因此每一次涉及到類簽名的修改,都會重新Deploy應用程序(結果就是經常性的OOM),甚至是直接重新啟動應用服務器。即使現在很多開發人員的硬件已經可以算的上高配置,但進行上述操作,仍然是一個非常耗時的操作。在我2004年的記憶中,當應用程序較大時,每天近二分之一的時間在等待服務器的啟動(或許另外一半時間在等待服務器的關閉)。
雖然Wicket1.2X以前的版本已經很好的支持POJO,而且對單元測試提供了很好的支持,但是當在應用服務器上運行時,仍然避免不了要修改代碼,所以服務器加載類仍然是一個問題,一件非常痛苦的事情。
在Wicket1.3中,Wicket小組使用了定制的ClassLoader結合Web應用服務器的Filter規范,從而提供新的Class熱加載功能,即使類的簽名有所變更(如Class中添加或移除了新的Field,Method),也能夠正確的加載新類。下面將用一個示例來演示Wicket1.3提供的這一新功能。
為了更好的分析Wicket1.3是如何實現Class熱加載功能,先將Wicket1.3.5的相關源代碼全部導入Eclipse中,作為一個Web項目,并配置一個Tomcat5作為測試用的Web服務器,具體的操作步驟就不在這里說明了,有興趣的讀者可以參考我在《Wicket開發指南》一書的相關章節,也可以參見這篇文章《導入Wicket項目》,從而在本地建立相應的開發環境。我這里使用的是Eclipse3.4,但Eclipse3.2和Eclipse3.3都可以,并沒有任何區別。本機建立后相應環境的界面如下:
Wicket項目放置了Wicket的源代碼,用來展示Wicket的熱加載功能。而Servers項目是Eclipse中WTP平臺用來定義Web服務器的配置項目,為了避免Tomcat自動Hot Deploy,需要關閉該功能。請打開Servers下面子目錄中的Server.xml,并將如下所示的默認配置進行修改。
原配置為:
<Context docBase="Wicket" path="/Wicket" reloadable="true" source="org.eclipse.jst.j2ee.server:Wicket"/> |
修改新配置為:
<Context docBase="Wicket" path="/Wicket" reloadable="false" source="org.eclipse.jst.j2ee.server:Wicket"/> |
通過將reloadable的屬性改為false,從而關閉Tomcat的Hot Deploy功能。
首先看一下Wicket自帶例子中一個簡單的Java類,代碼如下:
package org.apache.wicket.examples.helloworld; import org.apache.wicket.examples.WicketExamplePage; import org.apache.wicket.markup.html.basic.Label; /** * Everybody's favorite example! * * @author Jonathan Locke */ public class HelloWorld extends WicketExamplePage { /** * Constructor */ public HelloWorld() { add(new Label("message", "Hello World!")); } } |
使用WTP自帶的啟動服務器功能,以Debug模式啟動所配置的Tomcat,然后通過http://127.0.0.1:8080/Wicket/helloworld/來訪問這個人所均知的HelloWorld示例,從而在瀏覽器上看到"Hello World! "的字符串。
現在來修改一下HelloWorld類的代碼,添加一個方法addControls,將代碼變成:
package org.apache.wicket.examples.helloworld; Import org.apache.wicket.examples.WicketExamplePage; import org.apache.wicket.markup.html.basic.Label; /** * Everybody's favorite example! * * @author Jonathan Locke */ public class HelloWorld extends WicketExamplePage { /** * Constructor */ public HelloWorld() { addControls(); } private void addControls() { add(new Label("message", "New Hello World!")); } } |
上述的修改過程中,Eclipse會自動彈出警告框,說代碼簽名已經修改,不能熱加載。不必理會這個警告,點擊"Continue"按鈕即可。
但這一次,瀏覽器絲毫不給面子,仍然是老樣子,頁面上仍然顯示"Hello World",說明新個性的HelloWorld這個類沒有加載成功。
接下來再嘗試同樣的操作,從而體驗一下Wicket1.3如何支持類的熱加載。在進行操作之前,首先通過配置文件打開Wicket的類熱加載功能。修改Wicket項目中web.xml文件,將其中的
org.apache.wicket.protocol.http.WicketFilter
全部替換成
org.apache.wicket.protocol.http.ReloadingWicketFilter
從而開啟Wicket的類熱加載功能,然后重復剛才所做的操作,此時奇跡發生了,雖然我們修改了方法的簽名,但是這一次,在頁面正確的顯示了"New Hello World"字符串。到底Wicket是不是在霍格沃茲魔法學院學到什么魔術了嗎,為我們帶來如此的驚喜呢?后續文章中將會揭開它的神秘面紗。
值得要注意的是,雖然Wicket1.3中提供了新的Class熱加載功能,并且該功能在開發環境可以正常使用,有效的提高了開發效率,但是并不建議在上線系統中使用。
這是因為:
1. 它并不是一個完善的Class熱加載機制,因此出錯的機率仍然比較大,對于上線系統,它不夠完善、健壯,開發人員最好不要依賴于Wicket1.3的類熱加載機制。
2. 正式上線的系統,其類更新概率是非常小的,而Wicket采用文件掃描的方式檢查類是否被更新,會降低系統性能,在開發環境下,這種性能損失并不重要,但對于上線系統,可能造成大的性能波動,并嚴重降低性能表現。
posted on 2008-11-22 22:27 豬兒笨笨 閱讀(1973) 評論(2) 編輯 收藏 所屬分類: Java開發 、開源軟件 、Wicket