自定义ClassLoader
JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass(String name)方法:
loadClass(String name)方法再调用loadClass(String name, boolean resolve)方法:
- name - 类的二进制名称
- resolve - 如果该参数为 true,则分析这个类
如果ClassLoader并没有加载这个class,则调用findBootstrapClass0:
该方法会调用check()方法来判断这个类是否已经初始化,并且通过checkName(name)来判断由name指定的这个类是否存在
最后调用findBootstrapClass(name):
而这个findBootstrapClass方法是一个native方法,这是我们的root loader,这个载入方法并非是由JAVA所写,而是C++写的,它会最终调用JVM中的原生findBootstrapClass方法来完成类的加载。
如果上面两个都找不到,则使用findClass(name)来查找指定类名的Class:
JDK5.0中的说明:
使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。默认实现抛出一个 ClassNotFoundException。
所以,我们在自定义类中,只需要重写findClass()即可。
MyClassLoader类:
该类中通过调用defineClass(String name, byte[] b, int off, int len)方法来定义一个类:
注:MyClassLoader加载类时有一个局限,必需指定 .class文件,而不能指定 .jar文件。MainClassLoader类:
最后是一个简单的Test测试类:
- public Class<?> loadClass(String name) throws ClassNotFoundException {
- return loadClass(name, false);
- }
public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }
loadClass(String name)方法再调用loadClass(String name, boolean resolve)方法:
- name - 类的二进制名称
- resolve - 如果该参数为 true,则分析这个类
- 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;
- }
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:
- private Class findBootstrapClass0(String name)
- throws ClassNotFoundException
- {
- check();
- if (!checkName(name))
- throw new ClassNotFoundException(name);
- return findBootstrapClass(name);
- }
private Class findBootstrapClass0(String name) throws ClassNotFoundException { check(); if (!checkName(name)) throw new ClassNotFoundException(name); return findBootstrapClass(name); }
该方法会调用check()方法来判断这个类是否已经初始化,并且通过checkName(name)来判断由name指定的这个类是否存在
最后调用findBootstrapClass(name):
- private native Class findBootstrapClass(String name)
- throws ClassNotFoundException;
private native Class findBootstrapClass(String name) throws ClassNotFoundException;
而这个findBootstrapClass方法是一个native方法,这是我们的root loader,这个载入方法并非是由JAVA所写,而是C++写的,它会最终调用JVM中的原生findBootstrapClass方法来完成类的加载。
如果上面两个都找不到,则使用findClass(name)来查找指定类名的Class:
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- throw new ClassNotFoundException(name);
- }
protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }
JDK5.0中的说明:
使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。默认实现抛出一个 ClassNotFoundException。
所以,我们在自定义类中,只需要重写findClass()即可。
MyClassLoader类:
- 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();
- }
- }
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)方法来定义一个类:
- protected final Class<?> defineClass(String name, byte[] b, int off, int len)
- throws ClassFormatError
- {
- return defineClass(name, b, off, len, null);
- }
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类:
- 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();
- }
- }
- }
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测试类:
- public class Test
- {
- public Test() {
- System.out.println("Test");
- }
- public static void main(String[] args) {
- System.out.println("Hello World");
- }
- }
public class Test { public Test() { System.out.println("Test"); } public static void main(String[] args) { System.out.println("Hello World"); } }