类的热拔插功能该如何实现

比如我实例化了一个类,该类的class文件在该实例的生命期内被更新,当系统得知了这一消息后,终止该实例并载入新类后实例化该类。请问,我该如何让JVM从类文件中重新获取该类?谢谢

没有实际做过, 从看过的资料知道大概这样做:
1. 实现你自己的ClassLoader, 给这个loader加listener
2. listener监听loaded的文件last update time 属性来触发管理终止实例的事件
3. 终止实例以后, 把旧的loaded的class文件clear掉, 重新调用一次新的文件.

难点是在于怎样处理已经实例化的Class的引用, 统一终止掉?
在做某些server的应用中才会有这样的需求吧?

你可以参考一下resin和phoenix源代码, 它们都有Plug and Play的功能的.

你的疑题提得非常好,是这样的,我的系统是可以通过JMX进行远程更新的,通过MBean我可以让系统知道哪些模块需要重启(而不是服务器重启)。我的每个模块仅提供一组facade与外界通信,这些facade实际上由proxy模式实现,系统可跟踪每个被实例化的proxy。当更新消息到达时,proxy中的被代理对象被置换(销毁该对象),取而代之的是一个只能抛出ApplicationExpiredException的代理对象,这样就解决了处理对象引用的问题。
至于ClassLoader,是否有详细的资料?

I am curious about your jmx client UI, I have tried html adaptor from Sun and JBoss, and a swing based one( I don't remember, someone post on theserverside ), they did save me the effort to build my own console, but with some many things under some many categories to monitor/control, I need a better jmx console tool that's easy customizable.

Quake is right on the point about classloader, what we did here is throw exception if old instance is still refereneced. Sorry can't give you the code as it's not my own, but it's very basic once you read the jdk doc.

谢谢wys1978, 谢谢Jevang 的指正,看来我得仔细看一下JDK文档。
关于JMX client UI,我们的主要目的是用于返回错误报告及远程模块更新,从而降低实施成本。我们将使用HTML来完成UI,因为系统的维护界面并不复杂且可以使用系统已有的一些WEB组件,但这仅仅是一个初步设计,并未实现,因此不能向你提供更好的建议,请见谅。

JMX中有monitor功能,也许通过它来监察外界变化,同时将内部的Mbean重启一次。

你可以参考Jboss的源码,因为它也是侦测deploy目录下部署文件是否变化,一旦变化,就重新部署一次,我想这个原理你可以参考一用。

> 至于ClassLoader,是否有详细的资料?
http://jakarta.apache.org/bcel/index.html
其document中有一个例子,可以给classloader增加额外的工作。不知道是否适合你的应用情况。
jboss也是用的bcel

好象王森的JAVA深度历险有提到如何实现HOT DEPLOY

ClassLoader 是你需要的东西。
JVM 读取 Class 是从 ClassLoader 里读取的,当 ClassLoader 不同时,即使是读取同样的一个类,如 java.lang.String, JVM 都认为是不同的类(这也是出 ClassCastException 的原因之一)。

另外,ClassLoader 从1.2 以后,采用的是级联的方式(如果你要实现自己的ClassLoader也请遵守这个约定),如果当前ClassLoader 找不到 class 就会向上级(parent)请求 class. 如果找不到,就报 ClassNotFoundException.

还有,ClassLoader 的实现,一般都采用了 Cache 机制,常用的实现原理是,使用一个 Hashtable 来保存访问过的 class map. 格式大至是:[Class.getName(),Class]

如果是你自己的ClassLoader,你应该可以将这个map clean 掉,但如果你使用的是系统的 ClassLoader,那你就没法更新 Class 的 cache. 这样,你得到的永远都是 cache 中的class. 版本自然就不会更新。

清除 ClassLoader 中的 cache 只能在获取新对象时,才会比较发生作用。如果原来有对象实例(Object)已经对这个对象做了引用。对这样的情况我也不是很了解了,我想应该会报个错,最少会说两个 Class 的版本不对。 如果你做了试验,请post 上来,告诉大家吧

我也很想知道怎样实现,王森的那本书伤并没有提到。
另外再请教一个问题,如何实现context classloader即类适于jdbc的实现。(具体请看王森)的那本书!

我觉得更新并不困难,但是如何把所有的引用都替换就比较困难了

你们都把问题想简单了,类的热部署是很困难的,对于加载类的缓存不是由classloader自己维护的,而是由JVM维护,你可以看看defineClass是一个native方法就知道了,类的更新还涉及到很多复杂问题,比如 LinkageError,一个类更新了,所以依赖他编译出来的类都会受到影响。