Java动态从新加载Class
项目中使用到了动态从新加载Class的机制,做用是让一些代码上线以前能够在线上环境测试一下,固然,这是很是很差的测试机制,我刚来的时候也为这种机制感到惊讶—怎么能够在线上环境运行测试代码!后来通过了解,这么作的缘由有如下两个: html
既然咱们连测试机都没有,那么我就以为咱们的项目其实也没有想象中的重要,这么测就这么测吧~~
以前对ClassLoader没啥概念,google到一篇文章,翻译了一下而且作了一些补充,加深记忆
原文地址: java
---------------------------------------------------
ClassLoader
顾名思义,ClassLoader就是用来Load Class的,当一个Class被加载的时候,这个Class所引用到的全部Class也会被加载,并且这种加载是递归的,也就是说,若是A引用到B,B 引用到C,那么当A被加载的时候,B也会被加载,而B被加载的时候,C也会加载。如此递归直到全部须要的Class都加载好。
常见的ClassLoader: 测试
ClassLoader的代理层次关系
ClassLoader是以层次关系组织起来的,当你建立一个标准的Java ClassLoader的时候,你必须提供一个父ClassLoader。当一个ClassLoader须要加载一个Class的时候,它首先会让父 ClassLoader去加载这个Class,若是父ClassLoader不能加载这个Class,那么当前的ClassLoader才会本身去加载。
ClassLoader加载Class的步骤: google
从ClassLoader加载Class的步骤能够得知,若是你须要动态从新加载一个Class,那么你的ClassLoader必须跟上述标准流程有所区别,须要动态加载的Class不能交给父ClassLoader,不然你本身的ClassLoader将没有机会去加载这个Class(由于正常状况下父ClassLoader老是能加载到你所请求的Class)。
因此,若是你须要ClassLoader从新加载一个Class,重写findClass方法是起不到效果的,由于findClass在父 ClassLoader加载失败以后才会执行 spa
必须重写loadClass方法才能达到效果。
动态从新加载Class
Java内置的ClassLoader总会在加载一个Class以前检查这个Class是否已经被加载过,已经被加载过的Class不会加载第二次。所以要想从新加载Class,咱们须要实现本身的ClassLoader。
另一个问题是,每一个被加载的Class都须要被连接(link),这是经过执行ClassLoader.resolve()来实现的,这个方法是 final的,所以没法重写。Resove()方法不容许一个ClassLoader实例link一个Class两次,所以,当你须要从新加载一个 Class的时候,你须要从新New一个你本身的ClassLoader实例。
刚才说到一个Class不能被一个ClassLoader实例加载两次,可是能够被不一样的ClassLoader实例加载,这会带来新的问题: 翻译
这段代码会致使一个ClassCastException,由于在一个Java应用中,Class是根据它的全名(包名+类名)和加载它的 ClassLoader来惟一标识的。在上面的代码中object对象对应的Class和newInstance返回的实例对应的Class是有区别的: 代理
全名 | ClassLoader实例 | |
Object对象的Class | com.jenkov.MyObject | AppClassLoader实例 |
newInstance返回对象的Class | com.jenkov.MyObject | 自定义ClassLoader实例 |
解决的办法是使用接口或者父类,只从新加载实现类或者子类便可。 code
在本身实现的ClassLoader中,当须要加载MyObjectInterface或者MyObjectSuperclass的时候,要代理给父 ClassLoader去加载。 htm