一、基本概念
一个类是由加载它的类加载器和这个类本身来共同确定其在Java虚拟机中的唯一性。
二、什么是双亲委派模型
类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
双亲委派模型要求除了最顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器,在双亲委派模型中是采用组合关系来复用父类加载器的相关代码的。
三、双亲委派模型的实现
双亲委派模型实现的源码如下:
protected synchronized Class<?> loadClass(String name,boolean resolve)throws ClassNotFoundException{
//check the class has been loaded or not
Class c = findLoadedClass(name);
if(c == null){
try{
if(parent != null){
c = parent.loadClass(name,false);
}else{
c = findBootstrapClassOrNull(name);
}
}catch(ClassNotFoundException e){
//if throws the exception ,the father can not complete the load
}
if(c == null){
c = findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}
由源码可知,双亲委派模型的实现是在java.lang.ClassLoader类的loadClass()方法中。
类加载时,JVM会首先检查当前是否已经被加载过该类,如果没有加载且父加载器非空则会调用父类加载器的loadClass()方法,否则默认使用启动类加载器作为父加载器。如果父加载器无法完成加载(抛出ClassNotFoundException异常)则调用自己的findClass()方法进行加载。
四、双亲委派模型的优势
1、避免类的重复加载
每次进行类加载时,都尽可能由顶层的加载器进行加载,保证父类加载器已经加载过的类,不会被子类再加载一次,同一个类都由同一个类加载器进行加载,避免了类的重复加载。
2、防止系统类被恶意修改
通过双亲委派模型机制,能保证系统类由Bootstrap ClassLoader进行加载,用户即使定义了与系统类相同的类,也不会进行加载,保证了安全性。
五、如何破坏双亲委派模型
某些情况下,需要由子类加载器去加载class文件,这时就需要破坏双亲委派模型。要破坏双亲委派模型,可以通过重写ClassLoader类的loadClass()方法实现。
由于Java中所有类都默认继承Object类,但由于JDK的保护机制,系统类不能由自定义类加载器完成加载,需要对加载的类做判断,如果类名是java开头,则由拓展类加载器或引导类加载器进行加载。
典型的打破双亲委派模型的例子有Tomcat与OSGI,这部分需要详细了解可以参考源码。