在遵循父类委托机制的情况下,要实现自己的类加载器,只需要继承ClassLoader并重写他的findClass()方法。原理参见”父类委托机制[0]”章节。
现将如下源代码编译成.class文件,把com\bjsxt\test\HelloLoader.class放到D:\temp目录下
Java Code
| package com.bjsxt.test; public class HelloLoader { public static void sayLoader(){ System.out.println("I am in app classPath"); } } |
自定义一个类加载器,支持从指定目录读取.class文件并加载。
JavaCode
| package com.bjsxt.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * 自定义类加载器 * 支持从指定文件夹加载类 * @author ShadowfaxGHH * */ public class CustomSystemClassLoader extends ClassLoader { private String rootDir; public CustomSystemClassLoader(String rootDir) { this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 从自定义目录读取文件,转化为一个字节数组 byte[] classData = loadClassBytes(name); if (classData == null) { throw new ClassNotFoundException();//这个地方抛出异常会导致//一直向下到自定义类加载器,尝试加载,如果还加载不上报ClassNotFoundException } else { Class c = defineClass(name, classData, 0, classData.length); return c; } } private byte[] loadClassBytes(java.lang.String name) { String path = rootDir + "/" + name.replace(".", "/") + ".class"; InputStream is = null; ByteArrayOutputStream baos = null; try { is = new FileInputStream(path); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int ret = 0; while ((ret = is.read(buffer)) != -1) { baos.write(buffer, 0, ret); } return baos.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) is.close(); if (baos != null) baos.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } } |
使用如下代码进行测试,并且可以看到,自定义类加载器默认添加到父类委托机制的最底端。
JavaCode
| package com.bjsxt.test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 测试自定义的FileSystemClassLoader * @author ShadowfaxGHH * */ public class Test { public static void main(String[] args) { CustomClassLoader loader=new CustomClassLoader("D:/temp"); try { Class<?> clazz = loader.loadClass("com.bjsxt.test.HelloLoader"); ClassLoader classLoader = clazz.getClassLoader(); System.out.println(classLoader); //并且自定义类加载器默认添加到父类委托机制的最底端 while(classLoader.getParent()!=null){ System.out.println(classLoader.getParent()); classLoader=classLoader.getParent(); } //反射调用方法 Method declaredMethod = clazz.getDeclaredMethod("sayLoader", null); declaredMethod.invoke(null, null); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } |
![](https://img-blog.csdn.net/20170306153743941)
注意工程中不要再有HelloLoader.java文件,不然会被AppClassLoader加载上。
其实这里实现的功能在“父类委托机制”中已经实现了,这里只是讲解一下如何重写ClassLoader来实现自定义ClassLoader。