首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

java的热替换,有没大牛想写个热替换把从hibernate下拔上来的api文档里的超链接替换成小弟我们需要的

2012-12-25 
java的热替换,有没大牛想写个热替换把从hibernate上拔下来的api文档里的超链接替换成我们需要的??ClassLoa

java的热替换,有没大牛想写个热替换把从hibernate上拔下来的api文档里的超链接替换成我们需要的?


?ClassLoader 在加载类时有一定的层次关系和规则。在 Java 中,有四种类型的类加载器,分别为:BootStrapClassLoader、ExtClassLoader、AppClassLoader 以及用户自定义的 ClassLoader。这四种类加载器分别负责不同路径的类的加载,并形成了一个类加载的层次结构。

BootStrapClassLoader 处于类加载器层次结构的最高层,负责 sun.boot.class.path 路径下类的加载,默认为 jre/lib 目录下的核心 API 或 -Xbootclasspath 选项指定的 jar 包。ExtClassLoader 的加载路径为 java.ext.dirs,默认为 jre/lib/ext 目录或者 -Djava.ext.dirs 指定目录下的 jar 包加载。AppClassLoader 的加载路径为 java.class.path,默认为环境变量 CLASSPATH 中设定的值。也可以通过 -classpath 选型进行指定。用户自定义 ClassLoader 可以根据用户的需要定制自己的类加载过程,在运行期进行指定类的动态实时加载。

这四种类加载器的层次关系图如 图 1 所示。一般来说,这四种类加载器会形成一种父子关系,高层为低层的父加载器。在进行类加载时,首先会自底向上挨个检查是否已经加载了指定类,如果已经加载则直接返回该类的引用。如果到最高层也没有加载过指定类,那么会自顶向下挨个尝试加载,直到用户自定义类加载器,如果还不能成功,就会抛出异常。Java 类的加载过程如 图 2 所示。

图 2. Java 类的加载过程


?
java的热替换,有没大牛想写个热替换把从hibernate下拔上来的api文档里的超链接替换成小弟我们需要的
?

每个类加载器有自己的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅加载一次。不管该类有没有变化,下次再需要加载时,它只是从自己的缓存中直接返回已经加载过的类引用。

我们编写的应用类默认情况下都是通过 AppClassLoader 进行加载的。当我们使用 new 关键字或者 Class.forName 来加载类时,所要加载的类都是由调用 new 或者 Class.forName 的类的类加载器(也是 AppClassLoader)进行加载的。要想实现 Java 类的热替换,首先必须要实现系统中同名类的不同版本实例的共存,通过上面的介绍我们知道,要想实现同一个类的不同版本的共存,我们必须要通过不同的类加载器来加载该类的不同版本。另外,为了能够绕过 Java 类的既定加载过程,我们需要实现自己的类加载器,并在其中对类的加载过程进行完全的控制和管理。


?

好,现在我们把 Foo 类的 sayHello 方法更改为:


??

敏锐的读者可能会问,为何不用把 foo 转型为 Foo,直接调用其 sayHello 方法呢?这样不是更清晰明了吗?下面我们来解释一下原因,并给出一种更好的方法。

如果我们采用转型的方法,代码会变成这样:Foo foo = (Foo)cls.newInstance(); 读者如果跟随本文进行试验的话,会发现这句话会抛出 ClassCastException 异常,为什么吗?因为在 Java 中,即使是同一个类文件,如果是由不同的类加载器实例加载的,那么它们的类型是不相同的。在上面的例子中 cls 是由 HowswapCL 加载的,而 foo 变量类型声名和转型里的 Foo 类却是由 run 方法所属的类的加载器(默认为 AppClassLoader)加载的,因此是完全不同的类型,所以会抛出转型异常。

那么通过接口调用是不是就行了呢?我们可以定义一个 IFoo 接口,其中声名 sayHello 方法,Foo 实现该接口。也就是这样:IFoo foo = (IFoo)cls.newInstance(); 本来该方法也会有同样的问题的,因为外部声名和转型部分的 IFoo 是由 run 方法所属的类加载器加载的,而 Foo 类定义中 implements IFoo 中的 IFoo 是由 HotswapCL 加载的,因此属于不同的类型转型还是会抛出异常的,但是由于我们在实例化 HotswapCL 时是这样的:

HowswapCL cl = new HowswapCL("../swap", new String[]{"Foo"});

其中仅仅指定 Foo 类由 HotswapCL 加载,而其实现的 IFoo 接口文件会委托给系统类加载器加载,因此转型成功,采用接口调用的代码如下:


清单 4. 采用接口调用的代码

 

热点排行