自定义类加载器只需要继承java.lang.ClassLoader类,该类有两个核心方法,一个是loadClass(String, boolean),实现了双亲委派机制,还有一个方法是findClass,默认实现是空方法,所以我们自定义类加载器主要是重写findClass方法。
public class MyClassLoaderTest {
static class MyClassLoader extends ClassLoader{
//指定类加载器加载哪个路径下的类
private String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
//name为类的全限定名 (com.mafu.User) 把指定的路径下的.class文件读入到字节数组中
private byte[] loadByte(String name) throws Exception {
name = name.replace('.', '/');
FileInputStream fileInputStream = new FileInputStream(classPath + "/" + name + ".class");
int len = fileInputStream.available();
byte[] data = new byte[len];
fileInputStream.read(data);
fileInputStream.close();
return data;
}
//把.class文件二进制数组转为了一个Class对象
@Override
protected Class<?> findClass(String name){
try {
byte[] data = loadByte(name);
return defineClass(name,data,0,data.length);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
//测试 main方法
public static void main(String[] args) throws Exception {
MyClassLoader classLoader=new MyClassLoader("D:/test");
Class clazz=classLoader.loadClass("com.mafu.jvm.User");
System.out.println(clazz.getClassLoader().getClass().getName());
//打印结果为:com.mafu.jvm.MyClassLoaderTest$MyClassLoader
}
}
打破双亲委派机制
//重写父类的loadClass方法,其实就把委托父类加载的逻辑代码去掉,用自己写的类加载器加载
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
/** 去掉以下被注释的代码就不会向上委托给父类加载器去加载了
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
*/
if (c == null) {
//检查到当前类未被加载过就进来执行以下代码
long t0 = System.nanoTime();
long t1 = System.nanoTime();
if(name.startsWith("com.mafu.jvm")){
//如果是自己的包(指定的包下的类)就直接加载打破双亲委派
c = findClass(name);
}else {
//否则其他的就走双亲委派加载机制
c = this.getParent().loadClass(name);
}
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
// }
if (resolve) {
resolveClass(c);
}
return c;
}
}