请教:应用服务器如何识别被更新的class文件,是通过ClassLoader吗?

06-07-26 诸葛
我拿Tomcat5.0.28做的试验
public class Test{
static int a = 99;
static{
a = 5662;
System.out.println("类初始化");
}

public Test(){
System.out.println("创建了一个TTTTT的实例");
}
public static void stm(){
System.out.println("--------static-------!"+a);
}
public void m(){
System.out.println("--------nonstatic-------!"+a);
}
protected void finalize() throws Throwable {
super.finalize();
System.out.println("--------对象被释放---------!");
}
}

将创建一个Test类的对象,放到session中,
会打印出:
类初始化
创建了一个TTTTT的实例

然后执行m方法,打印出("--------nonstatic-------!5662
然后修改Test类,将m方法改为:
public void m(){
System.out.println("----modified----nonstatic-------!"+a);
}
再次执行,打印出的就就是新的方法中的内容:----modified----nonstatic-------!5662

但是没有打印出“类初始化”,也就是说没有执行static初始块。
同样的试验,发现static的方法也是被更新后的。
同时,我也尝试打印出Test.class.hashcode();,发现这个值一直没有变,这个方法是来自Object,Class类并没有override它,还有一些发现,我总结了一下tomcat的特点:
*Tomcat会识别应用目录下Class文件的更新操作,并通过某种机制将新的字节码替代旧的字节码
*Tomcat不会重新加载一个类,因为static块没有被执行
*Tomcat动态更新不允许增加方法、减少方法、增加/减少字段等操作。这些操作都会引起Tomcat崩溃。

至于Tomcat对servlet的更新相对就简单一些了,毕竟servlet实现了接口,而且都是完全由容器管理的,创建、更新、再次加载在理论上也都不是什么难事。可是对于Test这种完全自定义的类,实现动态更新让我困扰不已。小弟尝试从ClassLoader的角度分析这个问题,但是最后发现那样是没有办法达到这种效果的。小弟也尝试从Class类入手,现在还没有结果,请问哪位大虾能给小弟指点迷津,小弟不胜感激!

banq
2006-07-26 18:12
一般监视Web项目的web.xml文件,这是肯定的,其他则看具体容器了。

诸葛
2006-07-26 18:31
现在最让我弄不明白的是Tomcat这种服务器是什么更新的像Test这种自定义类的呢?按照我对ClassLoader的理解,是没办法实现Tomcat已经实现的那些功能的,请教banq。

诸葛
2006-07-26 19:00
现在Tomcat实现的功能如下:
*在class文件被更新的时候,如果被前后两个版本的class文件兼容(没有添加或者删除一个方法或者变量),Tomcat就会将最新的字节码加载,以后执行的都是更新后的字节码。
*不会再次初始化一个类(static块不会被执行)

表现在应用中,就是所有的对象执行的方法都是新的了,包括在更新前创建的对象。对象的hashcode()以及对象的getClass().hashcode()都没有变化。真让人匪夷所思。好像真的是一个类被reload了一样。


ps:因为一般spring都部署在应用服务器下,如Tomcat,所以reload的工作可以交给应用服务器去做。但是spring本身并没有reload类的功能,我研究这个的目的是希望给spring增加这个功能。

诸葛
2006-07-27 09:02
今天又尝试了一下不使用eclipse,而是将编译好的新版本的class文件手动拷贝到tomcat的目录下,结果发现代码也是被更新了的。感觉Tomcat这方面做的真的很不错,真希望在脱离了App Server的Spring也能有这种特性。

诸葛
2006-07-30 16:31
唉,这个问题没有人知道也没人关心吗?
我感觉如果把这个问题搞清楚了,对java语言的认识是会有很大提高的。现在我觉得可能是通过本地方法实现的更新。我朋友帮我找到一个开源项目,是jboss的一个子项目,希望感兴趣的和我一起多交流,我msn:deepnighttwo@hotmail.com
qq:393463165
^_^


下面是这个项目(javassist)的相关资料:
Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it. Unlike other similar bytecode editors, Javassist provides two levels of API: source level and bytecode level. If the users use the source-level API, they can edit a class file without knowledge of the specifications of the Java bytecode. The whole API is designed with only the vocabulary of the Java language. You can even specify inserted bytecode in the form of source text; Javassist compiles it on the fly. On the other hand, the bytecode-level API allows the users to directly edit a class file as other editors.

Aspect Oriented Programming: Javassist can be a good tool for adding new methods into a class and for inserting before/after/around advice at the both caller and callee sides.

Reflection: One of applications of Javassist is runtime reflection; Javassist enables Java programs to use a metaobject that controls method calls on base-level objects. No specialized compiler or virtual machine are needed.


https://sourceforge.net/project/showfiles.php?group_id=22866

这个页面里,你可以找到javassist的相关资料,是jboss的子项目。again:希望感兴趣的和我一起多交流,我msn:deepnighttwo@hotmail.com
qq:393463165


wwlhp@jdon.com
2006-08-13 22:30
关注中。

banq
2006-08-14 18:26
>是将编译好的新版本的class文件手动拷贝到tomcat的目录下,结果发现代码也是被更新了的

Tomcat这个功能也是间隔一段时间更新,不是时刻在更新,否则影响性能。我的经验:一般第一次更新,都能立即更新,但是紧接着再次更新,就不其作用了,非得等一段时间。

>真希望在脱离了App Server的Spring也能有这种特性
呵呵,脱离了APP server的Spring如果有,它不是也是另外一种App Server了?

Java所有加载机制都是通过classLoader加载,问题难点是,你要找到之前加载你的那个class的classloader,然后才能再此让其加载。