Wicket是Apache網(wǎng)站下面的一個(gè)頂級(jí)項(xiàng)目,是類似于ASP.Net的Web開(kāi)發(fā)框架,受到很多開(kāi)發(fā)者的好評(píng)。其最新的正式版本是1.3.5,正在開(kāi)發(fā)的版本是1.4。
1.3x版本系列是Wicket框架真正走向成熟的標(biāo)志版本,在該版本中提供了Stateless頁(yè)面和控件,以及DiskPageStore支持文件存取,以避免大量Stateful控件占用過(guò)多內(nèi)存引致OOM,而這一直是Wicket框架被人攻擊的關(guān)鍵點(diǎn)。另外對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),特別值得一提的則是它在1.3版本中支持了更好的Class熱加載。
其實(shí)J2EE開(kāi)發(fā)人員都知道在J2EE應(yīng)用程序的開(kāi)發(fā)中,最麻煩的往往是調(diào)試。雖然JDK已經(jīng)對(duì)類的熱加載提供了很好支持,當(dāng)JVM以調(diào)試模式啟動(dòng)的時(shí)候,可以在更改代碼以后,立即看到改動(dòng)后的效果,但是代碼的修改往往只限于方法的實(shí)現(xiàn),如果在類中添加戜刪除了一個(gè)Field或者是一個(gè)Method(該操作等于修改了類的簽名),那么JDK的熱加載就無(wú)法正常生效。雖然大部分的J2EE應(yīng)用服務(wù)器(如Tomcat,WebLogic)都聲稱自己提供了Hot Deploy功能,當(dāng)檢測(cè)到類文件被更新以后,可以重新加載相應(yīng)的Web應(yīng)用。但對(duì)于大部分的開(kāi)發(fā)人員來(lái)說(shuō),這種Hot Deploy功能更象是一個(gè)雞肋,看不出什么實(shí)際價(jià)值。比如說(shuō)如果在Session中放置了不支持序列化的對(duì)象,或者做了動(dòng)態(tài)類增強(qiáng),那么所謂的Hot Deploy幾乎是百分百出錯(cuò)。以Tapestry3.04版本為例(它使用了CGLib做類增強(qiáng)),在Tomcat5和WebLogic10環(huán)境上(其它版本應(yīng)該也是相同的,但沒(méi)有進(jìn)行過(guò)測(cè)試),沒(méi)有一次能夠正確的Hot Deploy。因此每一次涉及到類簽名的修改,都會(huì)重新Deploy應(yīng)用程序(結(jié)果就是經(jīng)常性的OOM),甚至是直接重新啟動(dòng)應(yīng)用服務(wù)器。即使現(xiàn)在很多開(kāi)發(fā)人員的硬件已經(jīng)可以算的上高配置,但進(jìn)行上述操作,仍然是一個(gè)非常耗時(shí)的操作。在我2004年的記憶中,當(dāng)應(yīng)用程序較大時(shí),每天近二分之一的時(shí)間在等待服務(wù)器的啟動(dòng)(或許另外一半時(shí)間在等待服務(wù)器的關(guān)閉)。
雖然Wicket1.2X以前的版本已經(jīng)很好的支持POJO,而且對(duì)單元測(cè)試提供了很好的支持,但是當(dāng)在應(yīng)用服務(wù)器上運(yùn)行時(shí),仍然避免不了要修改代碼,所以服務(wù)器加載類仍然是一個(gè)問(wèn)題,一件非常痛苦的事情。
在Wicket1.3中,Wicket小組使用了定制的ClassLoader結(jié)合Web應(yīng)用服務(wù)器的Filter規(guī)范,從而提供新的Class熱加載功能,即使類的簽名有所變更(如Class中添加或移除了新的Field,Method),也能夠正確的加載新類。下面將用一個(gè)示例來(lái)演示W(wǎng)icket1.3提供的這一新功能。
為了更好的分析Wicket1.3是如何實(shí)現(xiàn)Class熱加載功能,先將Wicket1.3.5的相關(guān)源代碼全部導(dǎo)入Eclipse中,作為一個(gè)Web項(xiàng)目,并配置一個(gè)Tomcat5作為測(cè)試用的Web服務(wù)器,具體的操作步驟就不在這里說(shuō)明了,有興趣的讀者可以參考我在《Wicket開(kāi)發(fā)指南》一書的相關(guān)章節(jié),也可以參見(jiàn)這篇文章《導(dǎo)入Wicket項(xiàng)目》,從而在本地建立相應(yīng)的開(kāi)發(fā)環(huán)境。我這里使用的是Eclipse3.4,但Eclipse3.2和Eclipse3.3都可以,并沒(méi)有任何區(qū)別。本機(jī)建立后相應(yīng)環(huán)境的界面如下:

Wicket項(xiàng)目放置了Wicket的源代碼,用來(lái)展示W(wǎng)icket的熱加載功能。而Servers項(xiàng)目是Eclipse中WTP平臺(tái)用來(lái)定義Web服務(wù)器的配置項(xiàng)目,為了避免Tomcat自動(dòng)Hot Deploy,需要關(guān)閉該功能。請(qǐng)打開(kāi)Servers下面子目錄中的Server.xml,并將如下所示的默認(rèn)配置進(jìn)行修改。
原配置為:
<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"/>
|
通過(guò)將reloadable的屬性改為false,從而關(guān)閉Tomcat的Hot Deploy功能。
首先看一下Wicket自帶例子中一個(gè)簡(jiǎn)單的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自帶的啟動(dòng)服務(wù)器功能,以Debug模式啟動(dòng)所配置的Tomcat,然后通過(guò)http://127.0.0.1:8080/Wicket/helloworld/來(lái)訪問(wèn)這個(gè)人所均知的HelloWorld示例,從而在瀏覽器上看到"Hello World! "的字符串。
現(xiàn)在來(lái)修改一下HelloWorld類的代碼,添加一個(gè)方法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!"));
}
}
|
上述的修改過(guò)程中,Eclipse會(huì)自動(dòng)彈出警告框,說(shuō)代碼簽名已經(jīng)修改,不能熱加載。不必理會(huì)這個(gè)警告,點(diǎn)擊"Continue"按鈕即可。
但這一次,瀏覽器絲毫不給面子,仍然是老樣子,頁(yè)面上仍然顯示"Hello World",說(shuō)明新個(gè)性的HelloWorld這個(gè)類沒(méi)有加載成功。
接下來(lái)再嘗試同樣的操作,從而體驗(yàn)一下Wicket1.3如何支持類的熱加載。在進(jìn)行操作之前,首先通過(guò)配置文件打開(kāi)Wicket的類熱加載功能。修改Wicket項(xiàng)目中web.xml文件,將其中的
org.apache.wicket.protocol.http.WicketFilter
全部替換成
org.apache.wicket.protocol.http.ReloadingWicketFilter
從而開(kāi)啟Wicket的類熱加載功能,然后重復(fù)剛才所做的操作,此時(shí)奇跡發(fā)生了,雖然我們修改了方法的簽名,但是這一次,在頁(yè)面正確的顯示了"New Hello World"字符串。到底Wicket是不是在霍格沃茲魔法學(xué)院學(xué)到什么魔術(shù)了嗎,為我們帶來(lái)如此的驚喜呢?后續(xù)文章中將會(huì)揭開(kāi)它的神秘面紗。
值得要注意的是,雖然Wicket1.3中提供了新的Class熱加載功能,并且該功能在開(kāi)發(fā)環(huán)境可以正常使用,有效的提高了開(kāi)發(fā)效率,但是并不建議在上線系統(tǒng)中使用。
這是因?yàn)椋?/font>
1. 它并不是一個(gè)完善的Class熱加載機(jī)制,因此出錯(cuò)的機(jī)率仍然比較大,對(duì)于上線系統(tǒng),它不夠完善、健壯,開(kāi)發(fā)人員最好不要依賴于Wicket1.3的類熱加載機(jī)制。
2. 正式上線的系統(tǒng),其類更新概率是非常小的,而Wicket采用文件掃描的方式檢查類是否被更新,會(huì)降低系統(tǒng)性能,在開(kāi)發(fā)環(huán)境下,這種性能損失并不重要,但對(duì)于上線系統(tǒng),可能造成大的性能波動(dòng),并嚴(yán)重降低性能表現(xiàn)。
點(diǎn)擊這里下載Word格式