自定义ClassLoader

自定义ClassLoader

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

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. }  
protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	//JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,如果一个Class已经被加载过,则直接从缓存中获取
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClass0(name);
		}
	    } catch (ClassNotFoundException e) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
}

如果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.     }  
private Class findBootstrapClass0(String name)
	throws ClassNotFoundException
    {
	check();
	if (!checkName(name))
	    throw new ClassNotFoundException(name);
	return findBootstrapClass(name);
    }

该方法会调用check()方法来判断这个类是否已经初始化,并且通过checkName(name)来判断由name指定的这个类是否存在
最后调用findBootstrapClass(name):
Java代码  
  1. private native Class findBootstrapClass(String name)   
  2.     throws ClassNotFoundException;  
private native Class findBootstrapClass(String name)
	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. }  
protected Class<?> findClass(String name) throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
}

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. }  
public class MyClassLoader extends ClassLoader {
    private String fileName;

    public MyClassLoader(String fileName) {
        this.fileName = fileName;
    }

    protected Class<?> findClass(String className) throws ClassNotFoundException {
        Class clazz = this.findLoadedClass(className);
        if (null == clazz) {
            try {
                String classFile = getClassFile(className);
                FileInputStream fis = new FileInputStream(classFile);
                FileChannel fileC = fis.getChannel();
                ByteArrayOutputStream baos = new
                        ByteArrayOutputStream();
                WritableByteChannel outC = Channels.newChannel(baos);
                ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                while (true) {
                    int i = fileC.read(buffer);
                    if (i == 0 || i == -1) {
                        break;
                    }
                    buffer.flip();
                    outC.write(buffer);
                    buffer.clear();
                }
                fis.close();
                byte[] bytes = baos.toByteArray();

                clazz = defineClass(className, bytes, 0, bytes.length);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return clazz;
    }
    private byte[] loadClassBytes(String className) throws
            ClassNotFoundException {
        try {
            String classFile = getClassFile(className);
            FileInputStream fis = new FileInputStream(classFile);
            FileChannel fileC = fis.getChannel();
            ByteArrayOutputStream baos = new
                    ByteArrayOutputStream();
            WritableByteChannel outC = Channels.newChannel(baos);
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            while (true) {
                int i = fileC.read(buffer);
                if (i == 0 || i == -1) {
                    break;
                }
                buffer.flip();
                outC.write(buffer);
                buffer.clear();
            }
            fis.close();
            return baos.toByteArray();
        } catch (IOException fnfe) {
            throw new ClassNotFoundException(className);
        }
    }
    private String getClassFile(String name) {
        StringBuffer sb = new StringBuffer(fileName);
        name = name.replace('.', File.separatorChar) + ".class";
        sb.append(File.separator + name);
        return sb.toString();
    }
}

该类中通过调用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.    }  
 protected final Class<?> defineClass(String name, byte[] b, int off, int len)
	throws ClassFormatError
    {
	return defineClass(name, b, off, len, null);
    }

注: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. }  
public class MainClassLoader {
    public static void main(String[] args) {
        try {
            MyClassLoader tc = new MyClassLoader("F:\\OpenLib\\");
            Class c = tc.findClass("Test");
            c.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace(); 
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace(); 
        }
    }
}

最后是一个简单的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. }  
public class Test
{
	public Test() {
		System.out.println("Test");
	}
	public static void main(String[] args) {
		System.out.println("Hello World");
	}
}

你可能感兴趣的:(自定义ClassLoader)