一、核心机制
在解决问题之前,我们需要先清楚下面这些机制
<1>、双亲委派原则
Java是运行在Java的虚拟机(JVM)中的。首先,我们编写的Java源代码被会被编译器编译成.class的字节码文件。然后再由ClassLoader负责将这些 .class 文件加载到JVM中去执行。
当某个 ClassLoader 需要加载某个 .class 文件时,它首先把这个任务委托给他的上级 ClassLoader ,递归这个操作,如果上级的 ClassLoader 没有加载,自己才会去加载这个类。
JVM中提供了三层的 ClassLoader:
ClassLoader | 作用以及加载范围 |
---|---|
Bootstrap classLoader | c++编写,是用本地代码实现的类装入器,负责在虚拟机启动时加载Jdk核心类库(如:rt.jar、resources.jar、charsets.jar等)以及加载后两个类加载器。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。 |
ExtClassLoader | java编写,是一个普通的Java类,继承自ClassLoader类,负责加载{JAVA_HOME}/jre/lib/ext/目录下的所有jar包。 |
AppClassLoader | java编写,是Extension ClassLoader的子对象,负责加载应用程序classpath目录下的所有jar和class文件。 |
每次收到类加载请求时,先将请求委派给父类加载器完成(所有加载请求最终会委派到顶层的Bootstrap ClassLoader加载器中),如果父类加载器无法完成这个加载(该加载器的搜索范围中没有找到对应的类),子类尝试自己加载, 如果都没加载到,则会抛出 ClassNotFoundException 异常。
双亲委派原则在本质上,是为了避免动态重复加载而考虑的一个安全因素。很多系统的关键类,如String 已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String