什么是打破双亲委派机制呢?
那么这里第一步, 我们需要知道什么是双亲委派机制?
前面已经说了什么是双亲委派机制了, 那打破是怎么回事呢?
比如, 我现在有一个自定义类加载器, 加载的是~/com/lxl/jvm/User1.class类, 而在应用程序的target目录下也有一个com/lxl/jvm/User1.class, 那么, 最终User1.class这个类将被哪个类加载器加载呢? 根据双亲委派机制, 我们知道, 他一定是被应用程序类加载器AppClassLoader加载, 而不是我们自定义的类加载器, 为什么呢? 因为他要向上寻找, 向下委托. 当找到了以后, 便不再向后执行了.
我们要打破双亲委派机制, 就是要让自定义类加载器来加载我们的User1.class, 而不是应用程序类加载器来加载
接下来分析, 如何打破双亲委派机制呢? 双亲委派机制是在哪里实现的? 是在ClassLoader类的loadClass(…)方法实现的. 如果我们不想使用系统自带的双亲委派模式, 只需要重新实现ClassLoader的loadClass(…)方法即可. 下面是ClassLoader中定义的loadClass()方法. 里面实现了双亲委派机制
下面给DefinedClassLoaderTest.java增加一个loadClass方法, 拷贝上面的代码即可. 删除掉中间实现双亲委派机制的部分
这里需要注意的是, com.lxl.jvm是自定义的类包, 只有我们自己定义的类才从这里加载. 如果是系统类, 依然使用双亲委派机制来加载.
来看看运行结果:
调用了user1的sout方法
com.lxl.jvm.DefinedClassLoaderTest
现在User1方法确实是由自定义类加载器加载的了
源码:
package com.lxl.jvm;
import java.io.FileInputStream;
import java.lang.reflect.Method;
/**
* 自定义的类加载器
*/
public class DefinedClassLoaderTest extends ClassLoader{
private String classPath;
public DefinedClassLoaderTest(String classPath) {
this.classPath = classPath;
}
/**
* 重写findClass方法
*
* 如果不会写, 可以参考URLClassLoader中是如何加载AppClassLoader和ExtClassLoader的
* @param name
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadBytes(name);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private byte[] loadBytes(String name) throws Exception {
// 我们需要读取类的路径
String path = name.replace('.', '/').concat(".class");
//String path = "";
// 去路径下查找这个类
FileInputStream fileInputStream = new FileInputStream(classPath + "/" + path);
int len = fileInputStream.available();
byte[] data = new byte[len];
fileInputStream.read(data);
fileInputStream.close();
return data;
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
/**
* 直接执行findClass()...什么意思呢? 首先会使用自定义类加载器加载类, 不在向上委托, 直接由
* 自己执行
*
* jvm自带的类还是需要由引导类加载器自动加载
*/
if (!name.startsWith("com.lxl.jvm")) {
c = this.getParent().loadClass(name);
} else {
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
public static void main(String[] args) throws Exception {
DefinedClassLoaderTest classLoader = new DefinedClassLoaderTest("/Users/luoxiaoli");
Class<?> clazz = classLoader.loadClass("com.lxl.jvm.User1");
Object obj = clazz.newInstance();
Method sout = clazz.getDeclaredMethod("sout", null);
sout.invoke(obj, null);
System.out.println(clazz.getClassLoader().getClass().getName());
}
}
https://www.cnblogs.com/ITPower/p/13211490.html