论坛首页 Java企业应用论坛

java动态代码的实现以及Class的卸载

浏览 13845 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-01-11   最后修改:2009-03-16

 JavaWorld一篇题为 Add dynamic code to your application 的文章介绍了如何使用动态代理技术使普通的java源代码具有像jsp一样的动态编译效果,十分有趣。
  使用过jsp技术的程序员都知道,应用部署以后,我们是可以直接修改jsp源文件的。当客户请求这个被修改过的jsp文件时,web容器会自动监测出该jsp文件已经被更新,因此重新编译该jsp文件,向客户返回最新的信息。但是,对于一般的java源文件,如果我们仅仅修改源文件,而不重新编译部署的话,web容器是不会处理的。
   那我们可不可以让普通的java源文件也具有jsp一样的效果呢,也就是说,程序在运行过程中,我们一旦修改某个类的源文件,程序会自动监测出来,并重新编译该文件,同时进行重新连接,动态更新。答案是肯定的,而且方法并不复杂。主要思想是当执行一个接口的操作时,我们使用动态代理技术将其拦截,然后监测实现该接口的类的源文件是否已经更新,如果没有更新,则把方法交给相应的对象的方法执行,否则,我们重新编译该类的源文件,同时重新加载该类,然后,我们就可以通过该类获得最新的对象以执行相应的操作了。
    系统的总体架构是是一个Dynamic Proxy,而实现的重点是捕捉到接口方法时在调用invoke的时候如何动态编译和重新加载。编译我们可以使用java提供的com.sun.tools.javac.Main.compile方法(要将jdk lib目录下的tool.jar加入到classpath中),通过该方法我们可以将指定的源文件进行编译并将相应的class文件放置到指定的目录中。
     为了能够进行重新连接,我们必须要把原来已经被加载的类卸载,否则我们是不能够将最新的类加载到jvm中去的。但是,我们卸载时却不能指定把classloader装载的类中的某一个类卸载掉,因此,我们只好重新生成一个classloader,通过它来重新加载我们新编译好的class文件。在这里,URLClassLoader是一个很好的选择。

 

updated(2009-3-16):

   JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):

   - 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
   - 加载该类的ClassLoader已经被GC。
   - 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法.

   发表时间:2007-01-11  
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。
0 请登录后投票
   发表时间:2007-01-11  
动态加载class 不是什么好主意,可以说是一个馊主意。
0 请登录后投票
   发表时间:2007-01-12  
Godlikeme 写道
动态加载class 不是什么好主意,可以说是一个馊主意。
为什么不具体说说为什么是一个馊注意呢!
0 请登录后投票
   发表时间:2007-01-12  
感觉没必要~!
0 请登录后投票
   发表时间:2007-01-12  
调试的时候还是有点用的,webwork的quick start也有这方面的功能。

引用

jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。

如果仅仅是动态加载同一个类的更新版本呢?
0 请登录后投票
   发表时间:2007-01-12  

Dustin 写道:
 JavaWorld一篇题为 Add dynamic code to your application 的文章介绍了如何使用动态代理技术使普通的java源代码具有像jsp一样的动态编译效果,十分有趣。
  使用过jsp技术的程序员都知道,应用部署以后,我们是可以直接修改jsp源文件的。当客户请求这个被修改过的jsp文件时,web容器会自动监测出该jsp文件已经被更新,因此重新编译该jsp文件,向客户返回最新的信息。但是,对于一般的java源文件,如果我们仅仅修改源文件,而不重新编译部署的话,web容器是不会处理的。
   那我们可不可以让普通的java源文件也具有jsp一样的效果呢,也就是说,程序在运行过程中,我们一旦修改某个类的源文件,程序会自动监测出来,并重新编译该文件,同时进行重新连接,动态更新。答案是肯定的,而且方法并不复杂。主要思想是当执行一个接口的操作时,我们使用动态代理技术将其拦截,然后监测实现该接口的类的源文件是否已经更新,如果没有更新,则把方法交给相应的对象的方法执行,否则,我们重新编译该类的源文件,同时重新加载该类,然后,我们就可以通过该类获得最新的对象以执行相应的操作了。
    系统的总体架构是是一个Dynamic Proxy,而实现的重点是捕捉到接口方法时在调用invoke的时候如何动态编译和重新加载。编译我们可以使用java提供的com.sun.tools.javac.Main.compile方法(要将jdk lib目录下的tool.jar加入到classpath中),通过该方法我们可以将指定的源文件进行编译并将相应的class文件放置到指定的目录中。
     为了能够进行重新连接,我们必须要把原来已经被加载的类卸载,否则我们是不能够将最新的类加载到jvm中去的。但是,我们卸载时却不能指定把classloader装载的类中的某一个类卸载掉,因此,我们只好重新生成一个classloader,通过它来重新加载我们新编译好的class文件。在这里,URLClassLoader是一个很好的选择。

 

 

热部署还是很有用的,只是实施方案需要斟酌一下。



0 请登录后投票
   发表时间:2007-01-12  
虽然没有想出它合适的应用场景,
但是新颖的思路挺不错的.
说不定什么时候会用得上,留个印象先,挺好.
0 请登录后投票
   发表时间:2007-01-12  
dwangel 写道
调试的时候还是有点用的,webwork的quick start也有这方面的功能。

引用

jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。

如果仅仅是动态加载同一个类的更新版本呢?

如果旧的类的引用依旧存在,始终会内存不足的。hotspot 的机制就是如此,这是改不了的。PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等。
0 请登录后投票
   发表时间:2007-01-12  
引用
PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等


Tomcat等JSP容器都支持热部署,它们是否存在这样的问题?如果存在,它们是使用什么机制解决的呢?没有深入研究过Tomcat,迷惑中。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics