`
Dustin
  • 浏览: 314706 次
  • 性别: Icon_minigender_1
  • 来自: 广州/成都
社区版块
存档分类
最新评论

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

阅读更多

 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 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法.

分享到:
评论
20 楼 liuInsect 2012-08-31  
其实你没有说到“怎么卸载一个class文件”啊,只是说怎么让他被GC,但是GC的本身就是不确定的,有没有可以直接指定 “马上将class卸载掉”的方法呢?
19 楼 juyin 2007-01-15  
JDK6.0中加入对脚本语言的支持也应该有这种的考虑吧,只是由于脚本是解释执行的,比较好处理。
感觉还是有一定的应用场景
有没有更详细的资料?
18 楼 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而不是重新启动应用服务器,也会出现类似情况。

的确如此!
17 楼 歆渊 2007-01-14  
zkj_beyond 写道
jsp和java类是完全不一样的概念。

jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,
jsp改变以后,web容器只要把相应的servlet对象更新就好了。


而java呢?
可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????

java这类静态语言无法实现象asp,php,jsp的效果的。

同意, 动态替换代码必需重新构造新的对象实例才能生效, 所以基本上只有是无状态对象在容器中执行的情况下才有现实意义.
16 楼 zkj_beyond 2007-01-13  
jsp和java类是完全不一样的概念。

jsp->servlet 在web容器中,你的servlet是单例的,也是无状态的,线程安全的。也就是只有一个对象,
jsp改变以后,web容器只要把相应的servlet对象更新就好了。


而java呢?
可能这个类在你的应用中有n个实例,与这些实例单向,双向关联的又有n个实例。如果你修改了,这些jvm存在的老的实例对象怎么办????

java这类静态语言无法实现象asp,php,jsp的效果的。
15 楼 YuLimin 2007-01-13  
代理,面向接口编程
public interface Postman {
	
	void deliverMessage(String msg);
}


这个容易做到,难的是有没有办法做到动态接口动态实现之类的呢?
这在得Class.forName了?还是另有它法?
14 楼 Dustin 2007-01-12  
引用
那就研究一下,楼上的!


嗯,有机会的话一定会。
13 楼 Godlikeme 2007-01-12  
magice 写道
Godlikeme 写道
动态加载class 不是什么好主意,可以说是一个馊主意。
为什么不具体说说为什么是一个馊注意呢!

3年前就做过一个自动测试机,用的是动态生成unit Test类的测试逻辑,然后动态编译加载自动执行测试,对于这样的小工具还可以。再有就是热部署了。
对于应用来讲,是一个不顾一切的捣洞技术,带来了系统运行不稳定的一系列问题。比如SPRING框架下beanFactory肯定会有问题。
12 楼 hing007210 2007-01-12  
比较有创意,收藏
11 楼 galaxystar 2007-01-12  
那就研究一下,楼上的!
10 楼 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而不是重新启动应用服务器,也会出现类似情况。
9 楼 Dustin 2007-01-12  
引用
PermGen space 是 hotspot 存放永久生成(permanent generated)的数据的空间,包括类、intern string等


Tomcat等JSP容器都支持热部署,它们是否存在这样的问题?如果存在,它们是使用什么机制解决的呢?没有深入研究过Tomcat,迷惑中。
8 楼 kdekid 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等。
7 楼 LucasLee 2007-01-12  
虽然没有想出它合适的应用场景,
但是新颖的思路挺不错的.
说不定什么时候会用得上,留个印象先,挺好.
6 楼 adamzhao 2007-01-12  
<br/>
<strong>Dustin 写道:</strong><br/>
<div class='quote_div'> JavaWorld一篇题为 <a href='http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html'>Add dynamic code to your application</a> 的文章介绍了如何使用动态代理技术使普通的java源代码具有像jsp一样的动态编译效果,十分有趣。<br/>
  使用过jsp技术的程序员都知道,应用部署以后,我们是可以直接修改jsp源文件的。当客户请求这个被修改过的jsp文件时,web容器会自动监测出该jsp文件已经被更新,因此重新编译该jsp文件,向客户返回最新的信息。但是,对于一般的java源文件,如果我们仅仅修改源文件,而不重新编译部署的话,web容器是不会处理的。<br/>
   那我们可不可以让普通的java源文件也具有jsp一样的效果呢,也就是说,程序在运行过程中,我们一旦修改某个类的源文件,程序会自动监测出来,并重新编译该文件,同时进行重新连接,动态更新。答案是肯定的,而且方法并不复杂。主要思想是当执行一个接口的操作时,我们使用动态代理技术将其拦截,然后监测实现该接口的类的源文件是否已经更新,如果没有更新,则把方法交给相应的对象的方法执行,否则,我们重新编译该类的源文件,同时重新加载该类,然后,我们就可以通过该类获得最新的对象以执行相应的操作了。<br/>
    系统的总体架构是是一个Dynamic Proxy,而实现的重点是捕捉到接口方法时在调用invoke的时候如何动态编译和重新加载。编译我们可以使用java提供的com.sun.tools.javac.Main.compile方法(要将jdk lib目录下的tool.jar加入到classpath中),通过该方法我们可以将指定的源文件进行编译并将相应的class文件放置到指定的目录中。<br/>
     为了能够进行重新连接,我们必须要把原来已经被加载的类卸载,否则我们是不能够将最新的类加载到jvm中去的。但是,我们卸载时却不能指定把classloader装载的类中的某一个类卸载掉,因此,我们只好重新生成一个classloader,通过它来重新加载我们新编译好的class文件。在这里,URLClassLoader是一个很好的选择。</div>
<p> </p>
<p> </p>
<p>热部署还是很有用的,只是实施方案需要斟酌一下。<br/>
<br/>
<br/>
<br/>
</p>
5 楼 dwangel 2007-01-12  
调试的时候还是有点用的,webwork的quick start也有这方面的功能。

引用

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

如果仅仅是动态加载同一个类的更新版本呢?
4 楼 lamono 2007-01-12  
感觉没必要~!
3 楼 magice 2007-01-12  
Godlikeme 写道
动态加载class 不是什么好主意,可以说是一个馊主意。
为什么不具体说说为什么是一个馊注意呢!
2 楼 Godlikeme 2007-01-11  
动态加载class 不是什么好主意,可以说是一个馊主意。
1 楼 kdekid 2007-01-11  
jvm存放生成的class的heap是有限的,而一部分过去的class还存在引用而不会被gc。所以这样做最后的后果是导致 java.lang.OutOfMemoryError: PermGen space。

相关推荐

    java 动态编译打包 动态编译可以用于实现动态代码生成、动态加载、插件化等功能

    例如,OSGi(Open Service Gateway Initiative)框架就是一个著名的Java插件化解决方案,它利用动态编译和模块化概念,实现了服务的动态发现、加载和卸载。 4. **性能与安全性**:虽然动态编译提供了很多便利,但它...

    安卓安装卸载相关-Android利用设备管理器实现APP无法卸载功能.rar

    在安卓系统中,开发者可以通过利用设备管理器(Device Administration API)来实现应用程序的保护机制,使其变得难以或无法被用户常规方式卸载。这个技术主要适用于企业级应用,以确保公司的数据安全和应用策略得以...

    动态生成、编译、运行java文件

    在IT行业中,动态生成、编译以及运行Java文件是一项重要的技术,它允许程序在运行时创建新的Java代码并执行。这种技术广泛应用于元编程、插件系统、代码自动生成等场景,极大地提高了软件的灵活性和可扩展性。下面将...

    android U盘卸载所需文件

    通过`java.lang.Class`类和相关的API,我们可以动态地获取和调用类的方法,创建对象,修改字段值等。在Android开发中,反射常用于处理私有成员、非静态成员、以及不希望硬编码的依赖。 2. **U盘卸载**:在Android...

    java热加载Class文件

    总之,Java热加载Class文件是提高开发效率的有效手段,它通过动态替换和更新类,使得开发者能够在不重启JVM的情况下观察代码更改的效果。了解并掌握这项技术,对于提升Java开发者的生产力具有重要意义。

    捕捉应用被卸载卸载应用

    JNI是Java平台的一部分,允许Java代码和其他语言写的代码进行交互。通过JNI,我们可以在Java代码中调用C/C++代码,反之亦然。在这个场景下,我们将使用JNI来监听系统级的事件,如应用卸载。 1. **创建本地库**: ...

    JAVA CLASS文件查看器

    1. **逆向工程**:当开发者需要了解某个库或框架的内部工作原理,而原始源代码不可用时,可以使用此工具查看CLASS文件,从而实现反编译。 2. **错误调试**:在没有源代码的情况下,通过查看CLASS文件的字节码,可以...

    从JVM分析Java的类的加载和卸载机制

    Java虚拟机(JVM)是Java程序的核心执行引擎,它负责管理和执行Java代码。本文将深入探讨JVM如何处理Java类的加载和卸载机制,以及类的生命周期。 首先,让我们了解一下类的加载过程。当Java程序运行时,JVM会根据...

    Android程序监听自身被卸载

    在涉及到JNI(Java Native Interface)时,Android应用可以调用C/C++代码来执行一些低级别或性能敏感的任务。在监听卸载的场景中,JNI可能并不直接参与,但如果在卸载过程中需要执行一些特定的原生操作,例如清理...

    植物大战僵尸java源代码

    Java允许动态加载和卸载资源,如图像、音频和数据文件。在《植物大战僵尸》的源码中,你可能会看到关于如何有效加载和使用这些资源的代码。 总的来说,通过研究《植物大战僵尸》的Java源代码,初学者可以学习到Java...

    易语言JAVA调用 例子

    易语言JAVA调用是将Java代码与易语言程序进行交互的一种技术,这使得开发者能够利用易语言编写主程序,同时利用Java的丰富库资源。在本例子中,我们看到几个关键文件,它们分别是: 1. **Test.class**:这是一个...

    android应用卸载提示

    在Android操作系统中,应用卸载提示是开发者为了增强用户体验或者实现特定功能而设计的一种机制。当用户尝试卸载一个应用程序时,系统默认情况下不会显示任何提示,而是直接执行卸载操作。然而,开发者可以通过编程...

    动态加载类机制JAVA

    - 动态加载类可以实现安全的代码隔离,因为不同加载器加载的类被视为不同的类,即使它们有相同的全限定名。 10. OSGi(Open Services Gateway Initiative)框架: - OSGi是一个用于创建模块化Java应用的框架,它...

    ndk卸载实现弹出短信界面

    虽然我们在C/C++代码中编写了发送短信的逻辑,但由于Android的SMS服务是Java层的,所以我们仍然需要通过JNI调用Java方法来发送短信。这可能涉及到反射,因为某些API可能需要在特定的上下文中使用(例如,只能在主线...

    安卓安装卸载相关-监听APP被卸载.rar

    "监听APP被卸载.rar"这个压缩包可能包含了一些示例代码或库,帮助开发者实现这一功能。然而,由于无法直接查看具体内容,以下将根据描述和标签,详细介绍如何在Android中实现监听APP被卸载的功能。 首先,我们需要...

    Android应用卸载之后打开Android浏览器问卷调查

    在这个场景中,源码指的是实现BroadcastReceiver和启动浏览器的Java代码,而工具主要涉及Android Studio开发环境和Android SDK中的相关类库。 总结,要实现在Android应用卸载后打开问卷调查,我们需要创建一个静态...

    java调用插件代码.rar

    具体到压缩包中的`java调用插件代码.txt`文件,其内容可能包含了具体的代码实现、示例或教程,详细解释了如何在Java项目中应用上述概念。为了更深入的理解,建议打开文件查看源代码和相关文档。

    Java有根儿:Class文件以及类加载器.doc

    类加载器不仅负责从磁盘、网络或其他来源读取Class文件,还参与了类的动态加载和卸载过程,这在进行JVM调优和复杂应用设计时非常重要。 总的来说,理解和掌握Class文件结构、JVM的工作原理以及类加载器的功能对于...

    卸载自身进行scoket完整jni代码

    在Android开发中,有时我们需要实现一个特殊的需求,即在应用程序退出或者被用户卸载时执行特定的操作,例如发送数据到服务器、清理资源等。标题提到的"卸载自身进行socket完整JNI代码"就是一个这样的场景,它涉及到...

    java热加载Class文件.zip

    8. **性能和稳定性**:虽然热加载带来了便利,但可能会影响应用的性能和稳定性,因为动态加载和卸载类可能会导致内存占用增加,以及可能的并发问题。因此,在生产环境中谨慎使用热加载,或者仅在开发和测试阶段使用...

Global site tag (gtag.js) - Google Analytics