java类加载器和双亲委派加载机制

java类加载器分类详解

1、启动类加载器(Bootstrap ClassLoader):也叫根类加载器,加载对象是java的核心类库,把一些核心的Java类加载进JVM中,这个加载器使用原生代码C/C++实现,并不是继承java.lang.ClassLoader,它是所有其他类加载器的最终父类加载器,负责加载<JAVA_HOME>/jre/lib目录在JVM指定的类库。其实它属于JVM整体的一部分,JVN一启动就会将这些指定的类加载到内存中,避免以后过多的I/O操作,提高系统的运行效率。启动类加载起无法被Java 程序直接使用

2、扩展类加载器(Extension ClassLoader):加载的对象为Java的扩展库,即加载<JAVA_HOME>/jre/lib/ext目录里面的类。这个类由启动类加载器加载,但因为启动类加载器并非用Java实现,一句脱离Java体系,所以如果尝试调用来扩展类加载器的getParent()方法获取父加载器会得到null。然而,它的父加载器是启动类加载器。

3、应用程序类加载器(Application ClassLoader):亦叫系统类加载器(System ClassLoader),负责加载用户类路径(CLASSPATH)所指定的类库。如果程序没有自己定义累类加载器,就默认使用应用程序加载器。它也由启动类加载器加载,但它的父加载类被设置成了扩展类加载器。如果使用这个加载器,可通过ClassLoader.getSystemClassLoader()获取。一般来说,用户自定义的就是由APP ClassLoader加载的。

各类加载器之间的关系

以组合关系复用父类加载器的父子关系,注意,这里的父子关系并不是以继承关系实现的

类加载器的双亲委派加载机制(重点)

双亲委派模型会在类加载器加载类时首先委托给父类加载器加载,除非父类加载器不能加载自己才加载

这种模型要求,除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器。假如有一个类要加载进来,一个类加载器并不会马上尝试自己将其加载,而是委派给父类加载器,父类加载器收到后又尝试委派给其父类加载器,以此类推,直到委派给启动类加载器,这样一层层往上委派。只有当父类加载器反馈自己没法完成这个加载时,子加载器才会尝试自己加载。通过这个机制,保证了Java应用所使用的都是同一个版本的Java核心库的类,同时这个机制也保证了安全性。设想如果应用程序类加载器想要加载一个有破坏性的java.lang.System类,双亲委派模型会一层层向上委派,最终委派给启动类加载器,而启动类加载器检查到缓存中已经有了这个类,并不会加载这个有破坏性的System类。

过程如下图所示:
java类加载器和双亲委派加载机制

双亲委派模型的源码实现

主要体现在ClassLoader的loadClass()方法,思路很简单:先检查是否已经被加载,若没有被加载则调用父类的LoadClass()方法,若父类加载器为空,则默认使用启动类加载器作为父类加载器,如果父类加载器加载失败,抛出ClassNotFoundException异常后,调用自己的findClass()方法进行加载