背景
对于任意一个类,都需要由加载它的类加载器和这个类本身来一同确立在Java虚拟机中的唯一性
如果不是同一个类加载器加载,即使是相同的class文件,也会出现判断不同的情况,从而引发一些意想不到情况,为了保证相同的class文件,在使用的时候,是相同的对象,JVM设计的时候,采用了双亲委派的方式来加载类。
双亲委派模型
双亲委派模式的工作原理的是;如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务(它的搜索范围中没有找到所需的类),子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都不愿意干活,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成。
双亲委派模式优势
采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关系可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader
再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer
的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer
,而直接返回已加载过的Integer.class
,这样便可以防止核心API库被随意篡改。
破环双亲委派模型
双亲委派模型并不是一个强制性的约束模型,而是java设计者推荐给开发者的类加载器实现方式。在Java的世界中大部分的类加载器都遵循这个模型,但也有例外。
为什么要破坏双亲委派
因为在某些情况下父类加载器需要委托子类加载器去加载class文件。受到加载范围的限制,父类加载器无法加载到需要的文件,以Driver
接口为例,由于Driver接口定义在JDK当中的,而其实现由各个数据库的服务商来提供,比如mysql的就写了MySQL Connector
,那么问题就来了,DriverManager
(也由jdk提供)要加载各个实现了Driver
接口的实现类,然后进行管理,但是DriverManager
由启动类加载器加载,只能记载JAVA_HOME
的lib下文件,而其实现是由服务商提供的,由系统类加载器加载,这个时候就需要启动类加载器来委托子类来加载Driver
实现,从而破坏了双亲委派,这里仅仅是举了破坏双亲委派的其中一个情况。