JavaClassLoader的一些热运用

  由于一个JDBC的基本封装引来众多砖块,其实对本人来说是好事!毕竟能够学到点东西。由于在使用到Class.forName()方法,就进而对 Class Loader有了疑惑,因此查阅了一些资料,这里来进行个人学习的总结。不过如果有建议或者拍砖。本人非常感谢!

下面是我对Class Loader进行一点总结

在Java中,类的实例化流程分为两个部分:类的加载和类的实例化。类的加载分为显式加载和隐式加载。大家都知道使用new关键字创建类实例,那么new 其实属于隐式地包含了类的加载过程。那么什么又是显式的加载呢?其实Class.forName就是一个最常用的。不管隐式还是显式都是通过调用 ClassLoader类的loadClass方法来完成类的实际加载工作。但是如果直接调用ClassLoader的loadClass方法是一种不常 见的显式加载类的技术。但是现在也在一些框架中使用了。

这样看起来好像ClassLoade没什么内涵。但是细心去研究发现其实Java类加载器是有层次的。ClassLoader在加载类时有一定的层次关系 和规则。在Java中,有四种类型的加载器,分别是 Bootstrap class loader、Extensions class loader、System class loader以及用户自定义的类加载器。现在来看看上面四种类型的加载器的职责。
引用
1. Bootstrap Class loader:该类加载器层次结构的最高层,直接负责<JAVA_HOME>/lib目录下的的核心API或-Xbootclasspath 选项指定的jar包。

2. Extensions Class Loader:该类主要负责默认为<JAVA_HOME>/lib/ext目录或者-Djava.ext.dirs指定目录下的jar包加 载。

3. System class loader:主要负责加载路径为java.class.path,默认为环境变量CLASSPATH中设定的值。

4. 用户自定义的类加载:根据用户的需要定制自己的类加载过程,在运行期进行指定类的动态实时加载。
大致就这四种那个类的加载。问题是他们有层次。看看他们在加载过程:
加载类的顺序:
引用
Bootstrap Class loader --> Extensions Class Loader -->System class loader ---->用户自定义的类加载;他们都是在直接的加载路径上进行加载。
对类是否加载过进行判断的过程则是加载类的逆序。

每个类加载器都有直接的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅仅加载一次。不管该类有没有变化,下次再需要加载时候, 它只是从自己的缓存中直接返回已经加载过的类引用。我们自己编写的类默认情况下都是通过System ClassLoader进行加载的。当我们使用new关键字或者class.forName来加载类时,所有加载的类则调用 SystemClassLoader进行加载。
通过上面的分析大概知道了一点类的加载机制了吧。以及各自的加载路径。
引用
设想:
既然知道我们知道类的加载机制和不同加载路径。我们是否会想到一个这样的问题。就是我们常常用SVN类纪录代码的版本。我们能不能利用类的加载机制来尝试 加载一个类的不同版本的共存呢?利用不同类的加载机制和类加载机制的路径来加载该类的另外一个不同的版本呢?因此为了充分发挥用户自定义类加载机制,以下 将试试利用自己的类加载器,对类的过程进行加载和控制和管理。

实施步骤:
1. 编写自定义的类加载
分析得出编写自定义的类加载器,必须要去继承ClassLoader。
Java 代码 
  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.IOException;  
  5. import java.util.HashSet;  
  6.   
  7. /** 
  8.  * Description: 1. 要 实现同一个类的不同版本的共存,那么这些不同版本必须有不同的类加载器进行加载 
  9.  *              2. 不能采用默认的加载器来进行加载类 
  10.  * @author Developer 
  11.  */  
  12. public class CustomerClassLoader extends ClassLoader {  
  13.     private String basedir; //需要该类加载器直接加载的类文件的基目录  
  14.     private HashSet dynaclazz; //需要由该类加载器直接加载的类名  
  15.       
  16.     public CustomerClassLoader(String basedir,String[] clazz) throws IOException{  
  17.         super(null);//防止父类进行加载  
  18.         this.basedir = basedir;  
  19.         dynaclazz = new HashSet();  
  20.         loadClassByMe(clazz);  
  21.     }  
  22.       
  23.     /** 
  24.      *  
  25.      * @param clazns 
  26.      * @throws IOException  
  27.      */  
  28.     private void loadClassByMe(String[] clazns) throws IOException{  
  29.         for(int i=0;i<clazns.length ; i++){  
  30.             loadDirectly(clazns[i]);  
  31.             dynaclazz.add(clazns[i]);  
  32.         }  
  33.     }  
  34.     
  35.       
  36.      /** 
  37.       *  
  38.       * @param name 
  39.       * @return 
  40.      * @throws IOException  
  41.       */  
  42.     private Class loadDirectly(String name) throws IOException {  
  43.        Class cls = null;  
  44.        StringBuffer sb = new StringBuffer(basedir);  
  45.        String classname = name.replace('.', File.separatorChar)+".class";  
  46.        sb.append(File.separator + classname);  
  47.        File classF = new File(sb.toString());  
  48.        cls = instantiateClass(name,new FileInputStream(classF),classF.length());  
  49.        return cls;  
  50.     }  
  51.       
  52.     /** 
  53.      *  
  54.      * @param name 
  55.      * @param fileInputStream 
  56.      * @param len 
  57.      * @return 
  58.      * @throws IOException 
  59.      */  
  60.   
  61.     private Class instantiateClass(String name,  
  62.             FileInputStream fileInputStream, long len) throws IOException {  
  63.           byte[] raw = new byte[(int)len];  
  64.           fileInputStream.read(raw);  
  65.           fileInputStream.close();  
  66.         return  defineClass(name,raw,0,raw.length);  
  67.     }  
  68.       
  69.     protected Class loadClass(String name,boolean resolve)throws ClassNotFoundException{  
  70.         Class cls = null;  
  71.         cls = findLoadedClass(name);  
  72.          if(!this.dynaclazz.contains(name) && cls == null)  
  73.              cls = getSystemClassLoader().loadClass(name);  
  74.          if(cls == null)  
  75.              throw new ClassNotFoundException(name);  
  76.          if(resolve)  
  77.              resolveClass(cls);  
  78.         return cls;  
  79.           
  80.     }  
  81. }  
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashSet; /** * Description: 1. 要实现同一个类的不同版本的共存,那么这些不同版本必须有不同的类加载器进行加载 * 2. 不能采用默认的加载器来进行加载类 * @author Developer */ public class CustomerClassLoader extends ClassLoader { private String basedir; //需要该类加载器直接加载的类文件的基目录 private HashSet dynaclazz; //需要由该类加载器直接加载的类名 public CustomerClassLoader(String basedir,String[] clazz) throws IOException{ super(null);//防止父类进行加载 this.basedir = basedir; dynaclazz = new HashSet(); loadClassByMe(clazz); } /** * * @param clazns * @throws IOException */ private void loadClassByMe(String[] clazns) throws IOException{ for(int i=0;i<clazns.length ; i++){ loadDirectly(clazns[i]); dynaclazz.add(clazns[i]); } } /** * * @param name * @return * @throws IOException */ private Class loadDirectly(String name) throws IOException { Class cls = null; StringBuffer sb = new StringBuffer(basedir); String classname = name.replace('.', File.separatorChar)+".class"; sb.append(File.separator + classname); File classF = new File(sb.toString()); cls = instantiateClass(name,new FileInputStream(classF),classF.length()); return cls; } /** * * @param name * @param fileInputStream * @param len * @return * @throws IOException */ private Class instantiateClass(String name, FileInputStream fileInputStream, long len) throws IOException { byte[] raw = new byte[(int)len]; fileInputStream.read(raw); fileInputStream.close(); return defineClass(name,raw,0,raw.length); } protected Class loadClass(String name,boolean resolve)throws ClassNotFoundException{ Class cls = null; cls = findLoadedClass(name); if(!this.dynaclazz.contains(name) && cls == null) cls = getSystemClassLoader().loadClass(name); if(cls == null) throw new ClassNotFoundException(name); if(resolve) resolveClass(cls); return cls; } }
以上基本代码已经完成,如果有兴趣可以看看,写一个类来试试。看能不能替换。
如果真正能够明白,我想利用该机制能够很好的做好类的热运行。不在停止服务情况下,进行升级。
代码肯定不够好,希望各位好好拍。附件中有一个.pdf资料。想深入了解可以研究下。

参考的一些资料有:
http://en.wikipedia.org/wiki/Java_Classloader
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html
原文地址:https://www.cnblogs.com/danghuijian/p/4400333.html