Java的动态加载机制分析跟应用

Java的动态加载机制分析和应用
转载请注明出处http://chillwarmoon.iteye.com
要弄清楚动态加载(热部署),首先要明白以下几点:
(1)一个classLoader实例只能对一个类加载一次。
(2)通过defineClass方法,可以动态加载类文件的byte数组到classloader实例中
(3)ClassLoader的loadClass方法加载类的顺序是:先用bootstrap classLoader加载类,如果加载不到,则用extClassLoader加载类,最后用system classLoader加载类
(4)假设某个自定义的CustomClassLoader用defineClass加载类,并且CustomClassLoader并没有覆盖loadClass方法。CustomClassLoader加载一个实现了接口IA的类A,那么defineClass会调用父类的loadClass,加载接口IA到system ClassLoader中。然而A被加载到了CustomClassLoader的实例中。

基于以上前提,若想达到对类A的热部署,不需要覆盖loadClass方法,让system ClassLoader加载接口,所以在由system classLoader加载的类中(也就是面向开发人员的代码中)可以通过类型转换IA a=(IA)clazz.newInstance(); 来访问动态加载的A的实例。但是因为每个classLoader实例只能对类加载一次,所以每次动态加载的时候,都需要创建一个classLoader实例来加载实现。
在实际应用中还要考虑动态加载点,也就是说什么时候对那些需要热部署的类进行动态加载。在网络应用中,如果要对某个长链接进行自定义处理,那么可以在链接建立的时候动态加载类。对于短链接的话,可以通过JMX手动动态更新类。也可以通过某个定时器来动态加载。
用动态加载的观点来看远程过程调用,就是说本地保存远程的接口,该接口是由本地的system classloader加载进来的,实现类通过byte流传过来,然后用特定的classLoader实例来加载该实现类。因此实现了远程过程调用。
1 楼 bachmozart 2009-05-27  
可能是我理解的问题

远程调用不需要客户端自定义classloader,比如 Client A 存放一个类的存根,Server B存放实现

那么数据流动是这样的

A  ------(请求调用某个实现类,封装好的参数类名信息等)------>  B

B  -------(实现类被调用后返回的结果)-----------------> A

需要自定义classloader的只是 Server B服务器,启动时加载一次所有实现类的jar
2 楼 抛出异常的爱 2009-05-27  
classloader没有研究过
不过有没有可能把某个server端的class文件
传到客户端
并运行某个方法
(属性也有存在的必要)
像动态变化接口的实现一样.
3 楼 java.lang.Object 2009-05-28  
抛出异常的爱 写道
classloader没有研究过
不过有没有可能把某个server端的class文件
传到客户端
并运行某个方法
(属性也有存在的必要)
像动态变化接口的实现一样.

这个不太可能,因为可能这个类又引用了很多客户端没有的类,并且这个类还有本地方法。
4 楼 chillwarmoon 2009-05-30  
bachmozart 写道
可能是我理解的问题

远程调用不需要客户端自定义classloader,比如 Client A 存放一个类的存根,Server B存放实现

那么数据流动是这样的

A  ------(请求调用某个实现类,封装好的参数类名信息等)------>  B

B  -------(实现类被调用后返回的结果)-----------------> A

需要自定义classloader的只是 Server B服务器,启动时加载一次所有实现类的jar



感觉不是B将结果返回给A,而是B将class bytes返回给A,然后由A的classLoader来加在class bytes所对应的类。这个class loader可以自定义,也可以是system classloader,就看需求是什么样子的。
5 楼 chillwarmoon 2009-05-30  
java.lang.Object 写道
抛出异常的爱 写道
classloader没有研究过
不过有没有可能把某个server端的class文件
传到客户端
并运行某个方法
(属性也有存在的必要)
像动态变化接口的实现一样.

这个不太可能,因为可能这个类又引用了很多客户端没有的类,并且这个类还有本地方法。


如果客户端引用的类在客户端已经被加载或者存在这些类,那么就可以。而且加载所依赖类的时候,未初始化时,初始化时,运行时都有可能加载。所以如果被依赖的类在某个不可见的方法内,那么应该也是可以的。

但是有一点是,服务器端传过来的class bytes,如果对应的类是一些jdk里边的类,如java.lang.String,客户端加载时需要小心,应该是首先用本地的class loader(例如bootstrap classloader)加载。因为如果采用自定义的加载,可能会产生一些安全问题。例如服务器端有些破坏性的实现。如果被委派到bootstrap classloader加载,bootstrap classloader会检查已加载的类,发现如果加载了,就不用加载String了。