「JVM 类加载子系统」系列文章
对于类加载器,我们知道重点是loadClass
方法, 双亲委派模型也是在loadClass
方法里面实现的。loadClass
方法里面实际上去加载类的是findClass
方法。对于我们自定义的类加载器来说需要做到两点即可
ClassLoader
类ClassLoader
类中的findClass
方法自定义类加载器继承自ClassLoader
抽象类,然后定义一个构造方法,用来接收要加载的类名
xpublic class MyClassLoader extends ClassLoader {
private String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
}
xxxxxxxxxx
public class MyClassLoader extends ClassLoader {
protected Class<?> findClass(String name) {
try {
byte[] data = loadByte(name);
return defineClass(name, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private byte[] loadByte(String name) throws IOException {
String fileName = name.replace(".", "/").concat(".class");
FileInputStream fileInputStream = new FileInputStream(classPath + "/" + fileName);
int len = fileInputStream.available();
byte[] data = new byte[len];
int read = fileInputStream.read(data);
fileInputStream.close();
return data;
}
}
注意:测试 class 文件不能放到类路径下,不然会被应用程序类加载器加载!!
xxxxxxxxxx
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
MyClassLoader myClassLoader = new MyClassLoader("/Users/lfool/myself/temp/java/");
Class<?> c = myClassLoader.loadClass("com.lfool.myself.Test03");
Object obj = c.newInstance();
Method f = c.getDeclaredMethod("f", null);
f.invoke(obj, null);
System.out.println(c.getClassLoader().getClass().getName());
}
这里有一个问题,为什么自定义类加载器的父类加载器是 AppClassLoader??
首先,自定义类加载器继承ClassLoader
,调用自定义类加载器的构造函数之前会先去调用ClassLoader
的无参构造函数
protected ClassLoader() {
// 调用自身构造函数
this(checkCreateClassLoader(), getSystemClassLoader());
}
private ClassLoader(Void unused, ClassLoader parent) {
// 赋值 parent,此处的 parent 是 getSystemClassLoader() 的值,具体见下方
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
assertionLock = new Object();
} else {
parallelLockMap = null;
package2certs = new Hashtable<>();
assertionLock = this;
}
}
public static ClassLoader getSystemClassLoader() {
// 具体见下方
initSystemClassLoader();
if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkClassLoaderPermission(scl, Reflection.getCallerClass());
}
return scl;
}
private static synchronized void initSystemClassLoader() {
if (!sclSet) {
if (scl != null)
throw new IllegalStateException("recursive invocation");
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
if (l != null) {
Throwable oops = null;
// 此处调用的是 Launcher 中的 getClassLoader 方法,返回的是 ppClassLoader.getAppClassLoader(extcl)
scl = l.getClassLoader();
try {
scl = AccessController.doPrivileged(
new SystemClassLoaderAction(scl));
} catch (PrivilegedActionException pae) {
oops = pae.getCause();
if (oops instanceof InvocationTargetException) {
oops = oops.getCause();
}
}
if (oops != null) {
if (oops instanceof Error) {
throw (Error) oops;
} else {
// wrap the exception
throw new Error(oops);
}
}
}
sclSet = true;
}
}