Java_动态从新加载Class机制

Java动态从新加载Class 

    项目中使用到了动态从新加载Class的机制,做用是让一些代码上线以前能够在线上环境测试一下,固然,这是很是很差的测试机制,我刚来的时候也为这种机制感到惊讶—怎么能够在线上环境运行测试代码!后来通过了解,这么作的缘由有如下两个: html

  • 有些代码没有办法在本地进行测试,本地没有线上的环境
  • 咱们弱到连测试机都没有(这是重点)


    既然咱们连测试机都没有,那么我就以为咱们的项目其实也没有想象中的重要,这么测就这么测吧~~ 
    以前对ClassLoader没啥概念,google到一篇文章,翻译了一下而且作了一些补充,加深记忆 
原文地址: java

引用
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#classloader


--------------------------------------------------- 
ClassLoader 
    顾名思义,ClassLoader就是用来Load Class的,当一个Class被加载的时候,这个Class所引用到的全部Class也会被加载,并且这种加载是递归的,也就是说,若是A引用到B,B 引用到C,那么当A被加载的时候,B也会被加载,而B被加载的时候,C也会加载。如此递归直到全部须要的Class都加载好。 
    常见的ClassLoader: 测试

引用
* Bootstrap class loader:虚拟机运行时必需要用到的类的加载器,好比java.*。它一般是在虚拟机种用本地代码(如C)实现,在系统中用null表示。 
* Extension class loader:负责加载ext目录下的Class。 
* Application class loader:负责加载CLASSPATH上的类。



ClassLoader的代理层次关系 
    ClassLoader是以层次关系组织起来的,当你建立一个标准的Java ClassLoader的时候,你必须提供一个父ClassLoader。当一个ClassLoader须要加载一个Class的时候,它首先会让父 ClassLoader去加载这个Class,若是父ClassLoader不能加载这个Class,那么当前的ClassLoader才会本身去加载。 
    ClassLoader加载Class的步骤: google

  • 检查这个Class是否已经被加载过了
  • 若是没有被加载过,那么让父ClassLoader尝试去加载
  • 若是父ClassLoader没法加载,那么尝试使用当前ClassLoader加载


    从ClassLoader加载Class的步骤能够得知,若是你须要动态从新加载一个Class,那么你的ClassLoader必须跟上述标准流程有所区别,须要动态加载的Class不能交给父ClassLoader,不然你本身的ClassLoader将没有机会去加载这个Class(由于正常状况下父ClassLoader老是能加载到你所请求的Class)。 
    因此,若是你须要ClassLoader从新加载一个Class,重写findClass方法是起不到效果的,由于findClass在父 ClassLoader加载失败以后才会执行 spa

Java代码   收藏代码
  1. // First, check if the class has already been loaded  
  2.         Class c = findLoadedClass(name);  
  3.         if (c == null) {  
  4.         try {  
  5.         if (parent != null) {  
  6.             c = parent.loadClass(name, false);  
  7.         } else {  
  8.             c = findBootstrapClass0(name);  
  9.         }  
  10.         } catch (ClassNotFoundException e) {  
  11.             // If still not found, then invoke findClass in order  
  12.             // to find the class.  
  13.             c = findClass(name);  
  14.         }  
  15.     }  


    必须重写loadClass方法才能达到效果。 

动态从新加载Class 
    Java内置的ClassLoader总会在加载一个Class以前检查这个Class是否已经被加载过,已经被加载过的Class不会加载第二次。所以要想从新加载Class,咱们须要实现本身的ClassLoader。 
    另一个问题是,每一个被加载的Class都须要被连接(link),这是经过执行ClassLoader.resolve()来实现的,这个方法是 final的,所以没法重写。Resove()方法不容许一个ClassLoader实例link一个Class两次,所以,当你须要从新加载一个 Class的时候,你须要从新New一个你本身的ClassLoader实例。 
    刚才说到一个Class不能被一个ClassLoader实例加载两次,可是能够被不一样的ClassLoader实例加载,这会带来新的问题: 翻译

Java代码   收藏代码
  1. MyObject object = (MyObject)  
  2.     myClassReloadingFactory.newInstance("com.jenkov.MyObject");  


这段代码会致使一个ClassCastException,由于在一个Java应用中,Class是根据它的全名(包名+类名)和加载它的 ClassLoader来惟一标识的。在上面的代码中object对象对应的Class和newInstance返回的实例对应的Class是有区别的: 代理

  全名 ClassLoader实例
Object对象的Class com.jenkov.MyObject  AppClassLoader实例
newInstance返回对象的Class com.jenkov.MyObject 自定义ClassLoader实例



    解决的办法是使用接口或者父类,只从新加载实现类或者子类便可。 code

Java代码   收藏代码
  1. MyObjectInterface object = (MyObjectInterface)  
  2.     myClassReloadingFactory.newInstance("com.jenkov.MyObject");  
  3.   
  4. MyObjectSuperclass object = ( MyObjectSuperclass)  
  5.     myClassReloadingFactory.newInstance("com.jenkov.MyObject");  



    在本身实现的ClassLoader中,当须要加载MyObjectInterface或者MyObjectSuperclass的时候,要代理给父 ClassLoader去加载。 htm

相关文章
相关标签/搜索