自定义类加载器

loadClass方法实现了双亲委派模型。

  1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
  2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false); ).或者是调用bootstrap类加载器来加载。
  3. 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
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) { 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) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }

【自定义类加载器】我们重写findClass方法。
注意在运行的时候,复制项目target中的com.qunar.LoadTest的class文件。拷贝到根目录下,linux下即/com/qunar/LoadTest。然后删除项目目录下的该文件。
因为虽然我们重写了findClass加载地址,但是根据双亲委派模型,父加载器appclassloader会在项目下查找,如果找到对应class就会加载,自定义的类加载器就没用了。当然如果我们直接掉用findClass方法就会直接加载,不会向上查找了。
import java.io.FileInputStream; import java.lang.reflect.Method; public class Main { static class MyClassLoader extends ClassLoader { private String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; }/** * 将class文件转换成字节数组 */ private byte[] loadByte(String name) throws Exception { name = name.replaceAll("\\.", "/"); FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class"); int len = fis.available(); byte[] data = https://www.it610.com/article/new byte[len]; fis.read(data); fis.close(); return data; }/** * 通过类全名找到class文件,转换成字节数组,转化成class对象 */ @Override protected Class findClass(String name) throws ClassNotFoundException { try { byte[] data = https://www.it610.com/article/loadByte(name); return defineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); } }}public static void main(String args[]) throws Exception { MyClassLoader classLoader = new MyClassLoader(""); Class clazz = classLoader.loadClass("com.qunar.LoadTest"); Object obj = clazz.newInstance(); Method helloMethod = clazz.getDeclaredMethod("hello", null); helloMethod.invoke(obj, null); }}

public class LoadTest { public void hello() { System.out.println("恩,是的,我是由 " + getClass().getClassLoader().getClass() + " 加载进来的"); } }

    推荐阅读