2007-01-11
java动态代码的实现以及Class的卸载
关键字: dynamic code
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是一个很好的选择。
使用过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是一个很好的选择。
评论
juyin
2007-01-15
JDK6.0中加入对脚本语言的支持也应该有这种的考虑吧,只是由于脚本是解释执行的,比较好处理。
感觉还是有一定的应用场景
有没有更详细的资料?
感觉还是有一定的应用场景
有没有更详细的资料?
boogie
2007-01-14
kdekid 写道
Dustin 写道
引用
PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等
Tomcat等JSP容器都支持热部署,它们是否存在这样的问题?如果存在,它们是使用什么机制解决的呢?没有深入研究过Tomcat,迷惑中。
一个最典型的例子是,你在IDE中(包括 netbeans 和 ecilpse)不断 restart 某个webapp,特别是用到了 spring/hibernate 的 webapp,就会出现这个 error。这可能是由于 spring 对程序结束的清除工作做得不是很好。在实际的部署中,基于 spring 的程序如果单是重新deploy而不是重新启动应用服务器,也会出现类似情况。
的确如此!
歆渊
2007-01-14
zkj_beyond 写道
jsp和java类是完全不一样的概念。
jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,
jsp改变以后,web容器只要把相应的servlet对象更新就好了。
而java呢?
可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????
java这类静态语言无法实现象asp,php,jsp的效果的。
jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,
jsp改变以后,web容器只要把相应的servlet对象更新就好了。
而java呢?
可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????
java这类静态语言无法实现象asp,php,jsp的效果的。
同意, 动态替换代码必需重新构造新的对象实例才能生效, 所以基本上只有是无状态对象在容器中执行的情况下才有现实意义.
zkj_beyond
2007-01-13
jsp和java类是完全不一样的概念。
jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,
jsp改变以后,web容器只要把相应的servlet对象更新就好了。
而java呢?
可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????
java这类静态语言无法实现象asp,php,jsp的效果的。
jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,
jsp改变以后,web容器只要把相应的servlet对象更新就好了。
而java呢?
可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????
java这类静态语言无法实现象asp,php,jsp的效果的。
YuLimin
2007-01-13
代理,面向接口编程
这个容易做到,难的是有没有办法做到动态接口动态实现之类的呢?
这在得Class.forName了?还是另有它法?
public interface Postman {
void deliverMessage(String msg);
}
这个容易做到,难的是有没有办法做到动态接口动态实现之类的呢?
这在得Class.forName了?还是另有它法?
Dustin
2007-01-12
引用
那就研究一下,楼上的!
嗯,有机会的话一定会。
Godlikeme
2007-01-12
magice 写道
Godlikeme 写道
动态加载class 不是什么好主意,可以说是一个馊主意。
为什么不具体说说为什么是一个馊注意呢!3年前就做过一个自动测试机,用的是动态生成unit Test类的测试逻辑,然后动态编译加载自动执行测试,对于这样的小工具还可以。再有就是热部署了。
对于应用来讲,是一个不顾一切的捣洞技术,带来了系统运行不稳定的一系列问题。比如SPRING框架下beanFactory肯定会有问题。
hing007210
2007-01-12
比较有创意,收藏
galaxystar
2007-01-12
那就研究一下,楼上的!
kdekid
2007-01-12
Dustin 写道
引用
PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等
Tomcat等JSP容器都支持热部署,它们是否存在这样的问题?如果存在,它们是使用什么机制解决的呢?没有深入研究过Tomcat,迷惑中。
一个最典型的例子是,你在IDE中(包括 netbeans 和 ecilpse)不断 restart 某个webapp,特别是用到了 spring/hibernate 的 webapp,就会出现这个 error。这可能是由于 spring 对程序结束的清除工作做得不是很好。在实际的部署中,基于 spring 的程序如果单是重新deploy而不是重新启动应用服务器,也会出现类似情况。
Dustin
2007-01-12
引用
PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等
Tomcat等JSP容器都支持热部署,它们是否存在这样的问题?如果存在,它们是使用什么机制解决的呢?没有深入研究过Tomcat,迷惑中。
kdekid
2007-01-12
dwangel 写道
调试的时候还是有点用的,webwork的quick start也有这方面的功能。
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。
如果仅仅是动态加载同一个类的更新版本呢?
引用
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。
如果仅仅是动态加载同一个类的更新版本呢?
如果旧的类的引用依旧存在,始终会内存不足的。hotspot 的机制就是如此,这是改不了的。PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等。
Lucas Lee
2007-01-12
虽然没有想出它合适的应用场景,
但是新颖的思路挺不错的.
说不定什么时候会用得上,留个印象先,挺好.
但是新颖的思路挺不错的.
说不定什么时候会用得上,留个印象先,挺好.
adamzhao
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是一个很好的选择。
使用过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是一个很好的选择。
热部署还是很有用的,只是实施方案需要斟酌一下。
dwangel
2007-01-12
调试的时候还是有点用的,webwork的quick start也有这方面的功能。
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。
如果仅仅是动态加载同一个类的更新版本呢?
引用
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。
如果仅仅是动态加载同一个类的更新版本呢?
lamono
2007-01-12
感觉没必要~!
magice
2007-01-12
Godlikeme 写道
动态加载class 不是什么好主意,可以说是一个馊主意。
为什么不具体说说为什么是一个馊注意呢!
Godlikeme
2007-01-11
动态加载class 不是什么好主意,可以说是一个馊主意。
kdekid
2007-01-11
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。
- 浏览: 48993 次
- 性别:

- 来自: 广州/成都

- 详细资料
搜索本博客
最近加入圈子
最新评论
-
Two extractors couldn't ...
Update Scrubyt 0.3.4 to 0.4.01
-- by Dustin -
Bridge模式在JDBC中是如何 ...
哦。是这样的吧。JDBC有两个变化点。1.平台的变化2.数据库的变化。所以,这个 ...
-- by fireflyc -
Bridge模式在JDBC中是如何 ...
我觉得是jdbc的应用,实现DAO的时候用到了bridge模式吧,好像在哪里看到 ...
-- by crazycow -
背后的路【3】
一口气看完了...
-- by crazycow -
背后的路【2】
楼主有很多经历和我很像,希望能交个朋友,呵呵:)
-- by crazycow






评论排行榜