昊天

自定义ClassLoader

JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass(String name)方法:
Java代码  
  1. public Class<?> loadClass(String name) throws ClassNotFoundException {   
  2. return loadClass(name, false);   
  3.    }  

loadClass(String name)方法再调用loadClass(String name, boolean resolve)方法:
     - name - 类的二进制名称
     - resolve - 如果该参数为 true,则分析这个类
Java代码  
  1. protected synchronized Class<?> loadClass(String name, boolean resolve)   
  2.     throws ClassNotFoundException   
  3.     {   
  4.     // First, check if the class has already been loaded   
  5.     //JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,如果一个Class已经被加载过,则直接从缓存中获取   
  6.     Class c = findLoadedClass(name);   
  7.     if (c == null) {   
  8.         try {   
  9.         if (parent != null) {   
  10.             c = parent.loadClass(name, false);   
  11.         } else {   
  12.             c = findBootstrapClass0(name);   
  13.         }   
  14.         } catch (ClassNotFoundException e) {   
  15.             // If still not found, then invoke findClass in order   
  16.             // to find the class.   
  17.             c = findClass(name);   
  18.         }   
  19.     }   
  20.     if (resolve) {   
  21.         resolveClass(c);   
  22.     }   
  23.     return c;   
  24. }  

如果ClassLoader并没有加载这个class,则调用findBootstrapClass0:
Java代码  
  1. private Class findBootstrapClass0(String name)   
  2.     throws ClassNotFoundException   
  3.     {   
  4.     check();   
  5.     if (!checkName(name))   
  6.         throw new ClassNotFoundException(name);   
  7.     return findBootstrapClass(name);   
  8.     }  

该方法会调用check()方法来判断这个类是否已经初始化,并且通过checkName(name)来判断由name指定的这个类是否存在
最后调用findBootstrapClass(name):
Java代码  
  1. private native Class findBootstrapClass(String name)   
  2.     throws ClassNotFoundException;  

而这个findBootstrapClass方法是一个native方法,这是我们的root loader,这个载入方法并非是由JAVA所写,而是C++写的,它会最终调用JVM中的原生findBootstrapClass方法来完成类的加载。

如果上面两个都找不到,则使用findClass(name)来查找指定类名的Class:
Java代码  
  1. protected Class<?> findClass(String name) throws ClassNotFoundException {   
  2.     throw new ClassNotFoundException(name);   
  3. }  

JDK5.0中的说明:
使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。默认实现抛出一个 ClassNotFoundException。
所以,我们在自定义类中,只需要重写findClass()即可。
MyClassLoader类:
Java代码  
  1. public class MyClassLoader extends ClassLoader {   
  2.     private String fileName;   
  3.   
  4.     public MyClassLoader(String fileName) {   
  5.         this.fileName = fileName;   
  6.     }   
  7.   
  8.     protected Class<?> findClass(String className) throws ClassNotFoundException {   
  9.         Class clazz = this.findLoadedClass(className);   
  10.         if (null == clazz) {   
  11.             try {   
  12.                 String classFile = getClassFile(className);   
  13.                 FileInputStream fis = new FileInputStream(classFile);   
  14.                 FileChannel fileC = fis.getChannel();   
  15.                 ByteArrayOutputStream baos = new  
  16.                         ByteArrayOutputStream();   
  17.                 WritableByteChannel outC = Channels.newChannel(baos);   
  18.                 ByteBuffer buffer = ByteBuffer.allocateDirect(1024);   
  19.                 while (true) {   
  20.                     int i = fileC.read(buffer);   
  21.                     if (i == 0 || i == -1) {   
  22.                         break;   
  23.                     }   
  24.                     buffer.flip();   
  25.                     outC.write(buffer);   
  26.                     buffer.clear();   
  27.                 }   
  28.                 fis.close();   
  29.                 byte[] bytes = baos.toByteArray();   
  30.   
  31.                 clazz = defineClass(className, bytes, 0, bytes.length);   
  32.             } catch (FileNotFoundException e) {   
  33.                 e.printStackTrace();   
  34.             } catch (IOException e) {   
  35.                 e.printStackTrace();   
  36.             }   
  37.         }   
  38.         return clazz;   
  39.     }   
  40.     private byte[] loadClassBytes(String className) throws  
  41.             ClassNotFoundException {   
  42.         try {   
  43.             String classFile = getClassFile(className);   
  44.             FileInputStream fis = new FileInputStream(classFile);   
  45.             FileChannel fileC = fis.getChannel();   
  46.             ByteArrayOutputStream baos = new  
  47.                     ByteArrayOutputStream();   
  48.             WritableByteChannel outC = Channels.newChannel(baos);   
  49.             ByteBuffer buffer = ByteBuffer.allocateDirect(1024);   
  50.             while (true) {   
  51.                 int i = fileC.read(buffer);   
  52.                 if (i == 0 || i == -1) {   
  53.                     break;   
  54.                 }   
  55.                 buffer.flip();   
  56.                 outC.write(buffer);   
  57.                 buffer.clear();   
  58.             }   
  59.             fis.close();   
  60.             return baos.toByteArray();   
  61.         } catch (IOException fnfe) {   
  62.             throw new ClassNotFoundException(className);   
  63.         }   
  64.     }   
  65.     private String getClassFile(String name) {   
  66.         StringBuffer sb = new StringBuffer(fileName);   
  67.         name = name.replace('.', File.separatorChar) + ".class";   
  68.         sb.append(File.separator + name);   
  69.         return sb.toString();   
  70.     }   
  71. }  

该类中通过调用defineClass(String name, byte[] b, int off, int len)方法来定义一个类:
Java代码  
  1. protected final Class<?> defineClass(String name, byte[] b, int off, int len)   
  2. throws ClassFormatError   
  3.    {   
  4. return defineClass(name, b, off, len, null);   
  5.    }  

注:MyClassLoader加载类时有一个局限,必需指定.class文件,而不能指定.jar文件。MainClassLoader类:
Java代码  
  1. public class MainClassLoader {   
  2.     public static void main(String[] args) {   
  3.         try {   
  4.             MyClassLoader tc = new MyClassLoader("F:\\OpenLib\\");   
  5.             Class c = tc.findClass("Test");   
  6.             c.newInstance();   
  7.         } catch (ClassNotFoundException e) {   
  8.             e.printStackTrace();    
  9.         } catch (IllegalAccessException e) {   
  10.             e.printStackTrace();   
  11.         } catch (InstantiationException e) {   
  12.             e.printStackTrace();    
  13.         }   
  14.     }   
  15. }  

最后是一个简单的Test测试类:
Java代码  
  1. public class Test   
  2. {   
  3.     public Test() {   
  4.         System.out.println("Test");   
  5.     }   
  6.     public static void main(String[] args) {   
  7.         System.out.println("Hello World");   
  8.     }   
  9. }  

posted on 2012-02-16 09:39 昊天 阅读(2156) 评论(0)  编辑  收藏 所属分类: java


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

统计

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜