1、java默认有三种类加载器,BootstrapClassLoader、ExtensionClassLoader、App ClassLoader三种。
2、BootstrapClassLoader是嵌在JVM内核中的加载器,该加载器是用C++语言写的,主要负载加载JAVA_HOME/lib下的类库,启动类加载器无法被应用程序直接使用。ExtensionClassLoader是用JAVA编写,且它的父类加载器是Bootstrap,是由sun.misc.Launcher$ExtClassLoader实现的,主要加载JAVA_HOME/lib/ext目录中的类库。
3、ExtensionClassLoader是用亭盍誓叭JAVA编写,且它的父类加载器是Bootstrap,是由sun.misc.Launcher$ExtClassLoader实现的,主要加载JAVA_HOME/lib/ext目录中的类库。我们知道java中系统属性java.ext.dirs指定的目录由ExtClassLoader加载器加载,如果程序中没有指定该系统属性(-Djava.ext.dirs=sss/lib)那么该加载器默认加载$JAVA_HOME/lib/ext目录下的所有jar文件,通过程序来看下系统变量java.ext.dirs所指定的路径
4、App ClassLoader是应用程序类加载器,负责加载应用程序classpath目录下的所有jar和class文件。它的父加载器为Ext ClassLoader
5、三种类加载器的层次如下所示。
6、注意:类加载器的体系并不是“继承”体系,而是委派体系,大多数类加载器首先会到自己的parent中查找类或者资源,如果找不到才会到自己本地查找。类加载器的委托行为动机是为了避免相同的类被加载多次。测试如下
7、在这里可以看到,Application ClassLoader的父加载器确实是ExtClassLoader。我们在往上走一层,如果猜想没错的话,ExtClassLoader的父加载器应该是BootStrap ClassLoader。这里不是说ExtClassLoader没有父加载器,而是因为Bootstrap ClassLoader使用C++写的
8、类加载器的类图结构如下
9、下面进行源码分析
10、AppClassLoader与ExtClassLoader都是Lancher的内部类。除了启动类加载器Bootstrap ClassLoader,其他的类加载器都是ClassLoader的子类。AppClassLoader只能加载java.class.path路径下的class文件。
11、双亲委派模型:如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。我们分析下 源码
12、先检查是否已经被加载过,若没有加载则调用父类加载器的loadClass方法,若父类加载器不存在,则使用启动类加载器。如果父类加载器加载失败,则抛出异常之后看,再调用自己的findClass方法进行加载。