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采用文件扫描的方式检查类是否被更新,会降低系统性能,在开发环境下,这种性能损失并不重要,但对于上线系统,可能造成大的性能波动,并严重降低性能表现。
点击这里下载Word格式