在遵循父类委托机制的情况下,要实现自己的类加载器,只需要继承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();
}
}
}
|

注意工程中不要再有HelloLoader.java文件,不然会被AppClassLoader加载上。
其实这里实现的功能在“父类委托机制”中已经实现了,这里只是讲解一下如何重写ClassLoader来实现自定义ClassLoader。