双亲委派机制 parents delegate
在Java中,一个类如果要被执行首先会被编译成.class文件,然后由类加载器ClassLoader加载到JVM中。因为在Java中有好几个类加载器,那么由哪个类加载器来加载这个.class文件便需要一种机制来使其规范运行。这个机制便是双亲委派机制。
为什么叫"双亲",目前主流说法是翻译的问题,因为可以看到parents是复数。也可以这样理解:当加载一个普通类时,Application ClassLoader会向上面的父加载器委派两次,即Extension ClassLoader, Bootstrap ClassLoader。
Java中有几个类加载器,层级关系如图所示:
每种加载器的作用:
- Bootstrap ClassLoader:主要负责加载Java中的核心类,位于 %JRE_HOME%\lib 的rt.jar、resources.jar、charsets.jar和class等, 比如lang包,math包等等。
- Extension ClassLoader:主要负责加载 %JRE_HOME%\lib\ext 下的jar包和class文件。
- Application ClassLoader:主要负责加载当前应用的classpath下的所有类。
- User ClassLoader:用户自定义的类加载器,可以加载指定路径下的class文件。
对每层而言上一层为父加载器。因此除了Bootstrap ClassLoader外,所有类加载器都有父加载器。
双亲委派机制:当一个类加载器收到了类加载的请求后,它不会立刻去加载,而是把这个请求委派给它的父加载器去加载。只有当父加载器加载不了的时候,才由当前这个加载器去加载。
当用户写的程序中,比如自己定义了一个Student类,如果没有自定义类加载器的话,首先委托到Application Classloader,这个加载器再往上委托,但很明显上层的两个父加载器的加载范围不包括自定义类,所以加载失败。便最终由Application ClassLoader进行加载。
使用双亲委派机制的好处:
- 通过委派的方式,可以避免类的重复加载。因为当父加载器成功加载一个类时,子加载器便不必再重复加载。
- 通过这种方式可以保证系统安全性。比如如果黑客在你系统代码里自定义了一个有破坏功能的String类,在双亲委派的机制下,java.lang.String加载请求会向上一直被委派到Bootstrap ClassLoader,这个类加载器其实会去加载rt.jar包下的String类,也就是“正宗”的String类,从而达到了一个保护作用。
自定义类加载器:继承ClassLoader,并重写findClass()方法实现自己想要的逻辑。