猪儿笨笨的文档

主要是个人的一些思考和技术文章,还有许多翻译的文档

 

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


 点击这里下载Word格式

posted on 2008-11-22 22:27 猪儿笨笨 阅读(1869) 评论(2)  编辑  收藏 所属分类: Java开发开源软件Wicket

评论

# re: Wicket1.3中Class热加载功能--使用篇 [未登录] 2008-11-23 10:51 ivin

不错哦。现在每天开发的时候都得重启小猫n次,挺烦人的,有时候java文件一个小小的改动都得重启一下。这样就不用总start server了
  回复  更多评论   

# re: Wicket1.3中Class热加载--使用篇 [未登录] 2009-02-11 11:00 li

这些框架没有一个好用的,上手都很难,我觉得客户端html标签里可以采用像flex那样的collector,renderer,或者自定义一些属性跟数据库表关联,例如
<select id="" dataTable="" dataColumn="" dataRow="" collector=""
listRender="">,服务器端采用一定格式写一个数据库的文件,比如**.adp,里面的sql文法可以自己定义,当客户端提交表单时,servlet可以拦截并指定用哪个.adp文件,返回的数据集结果就是根据客户端的render自动填充,完全不用写任何一个额外的java文件,web.xml文件也不需要配置,这是最好的方案  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

常用链接

留言簿(18)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜