ClassLoader-2

ClassLoader

URLClassLoader

AppClassLoader

ExtClassLoader

1、将ExtClassLoader作为父加载器传给AppClassLoder,而ExtClassLoader的父加载器传的是null

2、ExtClassLoader加载的目录是:java.ext.dirs,AppClassLoader加载的目录是java.class.path

3、这里再说一下AppClassLoder,ExtClassLoader extentds URLClassLoader,父类和父加载器是两个概念,父加载器是组合模式,持有父加载器的引用

-----------------------------------------

加载流程

从前一节main方法的执行可以看到,加载一个普通类说起,是用系统类加载器,即AppClassLoader

-> AppClassLoader.loadClass->ClassLoader.loadClass -> parent.loadClass

-> ExtClassLoader.loadClass->ClassLoader.loadClass -> findBootstrapClassOrNull -> null -> findClass

  -> URLClassLoader.findClass -> Resource res = ucp.getResource(path, false);  //在java.ext.dirs目录下加载不到用户的类 -> res == null -> throw ClassNotFoundException

-> AppClassLoader.loadClass catch ClassNotFoundException -> null -> findClass

  -> URLClassLoader.findClass -> res != null

  -> ClassLoader.defineClass -> native ClassLoader.defineClass1 -> load success

所以最终是流程是:

1、AppClassLoader.loadClass:调用父类ClassLoader.loadClass方法

2、parent.loadClass:递归调用父加载器 ExtClassLoader.loadClass -> BootStrapClassLoader.loadClass,加载用户类失败

3、ExtClassLoader findClass:URLClassLoader.findClass: java.ext.dirs目录下加载class文件失败  -> throw ClassNotFound,在AppClassLoader Catch

4、AppClassLoader findClass:URLClassLoader.findClass:java.class.path目录下加载class文件成功,并加载二进制流

5、ClassLoader defineClass:URLClassLoader.findClass中再调用ClassLoader.defineClass,传入二进制流,完成Class组装

总结:

1、通过上述流程可以看到,其实ClassLoader已经干了大部分的活,ClassLoader实现了委派机制,

2、子类只需要实现findClass,findClass方法中:1需要加载class文件(二进制流),2调用ClassLoader.defineClass传入二进制流

3、AppClassLoader、ExtClassLoader 都是继承自URLClassLoader.findClass,只是在初始化的时候将加载目录的urls传给了URLClassLoader,URLClassLoader.findClass通过urls加载class文件

自定义加载器

从上面的总结2可以看出,自定义加载器只需要实现findClass完成class文件的加载,然后在调用ClassLoader.defineClass传入二进制流即可再来看看官方推荐: The network class loader subclass must define the methods {@link #findClassfindClass} andloadClassDatato load a class from the network. Once it has downloaded the bytes that make up the class, it should use the method {@link #defineClassdefineClass} to create a class instance. A sample implementation is:

class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection }}

以上就是个标准的自定义加载器了:

1、定义defineClass,加载class文件二进制流  2、调用父类ClassLoader.defineClas,传入二进制流,完成类的加载

使用:

NetworkClassLoader loader = new NetworkClassLoader();

loader.loadClass("com....");

注意:new NetworkClassLoader()并未传入父加载器,但是会调用ClassLoader的无参构造方法通过getSystemClassLoader传入系统类加载器,即AppClassLoader

    所以,自定义加载器若没有特殊指定父加载器,则默认父加载器为AppClassLoader

    当父加载器:BootStrapClassLoader,ExtClassLoader,AppClassLoader都加载不到时,触发自身的findClass方法

你可能感兴趣的:(ClassLoader-2)