「JVM 类加载子系统」系列文章
对于类加载器,我们知道重点是loadClass方法, 双亲委派模型也是在loadClass方法里面实现的。loadClass方法里面实际上去加载类的是findClass方法。对于我们自定义的类加载器来说需要做到两点即可
ClassLoader类ClassLoader类中的findClass方法自定义类加载器继承自ClassLoader抽象类,然后定义一个构造方法,用来接收要加载的类名
xpublic class MyClassLoader extends ClassLoader {
private String classPath;
public MyClassLoader(String classPath) { this.classPath = classPath; }}xxxxxxxxxxpublic 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 文件不能放到类路径下,不然会被应用程序类加载器加载!!
xxxxxxxxxxpublic 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; }}