理解类加载器的双亲委派模式

一、JVM中的几种类加载器(Class Loader)

  JVM有以下几种类加载器,如图1。图中的启动类加载器为根类加载器,其子类加载器均继承自抽象类。
启动类加载器(Bootstrap ClassLoader):Java应用启动时,加载$JAVA_HOME/lib或 -Xbootclasspath指定的路径中的类文件;
扩展类加载器(Extension ClassLoaser):由sun.misc.Launcher$ExtClassLoader实现,负责加载$JAVA_HOME/lib/ext或java.ext.dirs指定路径的类库;
应用程序类加载器(Application ClassLoader):又称系统类加载器,由sun.misc.Launcher$AppClassLoader实现,是ClassLoader.getSystemClassLoader()的返回值。
注:这里的父子关系是使用组合(Composition)关系而非继承(Inheritance)关系来实现的,构造函数形如new XXClassLoader(xx, ParentClassLoader)

(图1、JVM中的几种类加载器)
 

二、在JVM中确定唯一的类

1、在JVM中唯一确定Java类(类的隔离)

  在JVM中,一个类的唯一性是由类本身及加载该类的类加载器决定的,因此即使完全相同的class文件,使用不同的类加载器加载,也会是互相独立的类,即类是互相隔离。
  在下面代码中,创建了一个与AppClassLoader同级的类加载器,程序中分别使用AppClassLoader和创建的ClassLoader对象加载了同一个类文件,因此隔离这两个类对象是隔离的,尽管他们加载的是同一个类文件。

/* Clazz in com.guanjianzhuo.parentdelegation.entity */
public class Clazz {
@Override
public String toString() {
return “Clazz Object.”;
}
}
 
/* ClassCompareDemo In com.guanjianzhuo.parentdelegation */
import com.guanjianzhuo.parentdelegation.entity.Clazz;
public class ClassCompareDemo {
public static void main(String[] args) {
URL url = ClassCompareDemo.class.getClassLoader().getResource(“”);
URL[] urls = new URL[]{url};
try(URLClassLoader classLoader = new URLClassLoader(urls, ClassLoader.getSystemClassLoader().getParent())) {
// 使用AppClassLoader加载
Object clazz0 = new Clazz();
// 使用与AppClassLoader同级的类加载器加载
Object clazz1 = classLoader.loadClass(“com.guanjianzhuo.parentdelegation.entity.Clazz”).newInstance();
System.out.println(“clazz0.toString(): ” + clazz0 + “, class: ” + clazz0.getClass().getName());
System.out.println(“clazz1.toString(): ” + clazz1 + “, class: ” + clazz1.getClass().getName());
System.out.println(“clazz1 instanceof Clazz: ” + (clazz1 instanceof Clazz));
} catch (Exception e) {
e.printStackTrace();
}
}
}
 
/* console info: */
clazz0.toString(): Clazz Object., class: com.guanjianzhuo.parentdelegation.entity.Clazz
clazz1.toString(): Clazz Object., class: com.guanjianzhuo.parentdelegation.entity.Clazz
clazz1 instanceof Clazz: false

 

2、什么是双亲委派模型(Parent-Delegation Model)?为什么使用双亲委派模型?

  JVM中加载类机制采用的是双亲委派模型,顾名思义,在该模型中,子类加载器收到的加载请求,不会先去处理,而是先把请求委派给父类加载器处理,当父类加载器处理不了时再返回给子类加载器加载;
        其类加载流程图如下:
(图2、JVM双亲委派模型类加载流程图)
  为什么使用双亲委派模型?
  因为安全。使用双亲委派模型来组织类加载器间的关系,能够使类的加载也具有层次关系,这样能够保证核心基础的Java类会被根加载器加载,而不会去加载用户自定义的和基础类库相同名字的类,从而保证系统的有序、安全。
 

三、应用:容器中不同应用的隔离

1、应用场景

  双亲委派模型能保证Java类在内存中只会保存一份。但是,双亲委派模型并不是一个强制性模型,有时候为了程序的灵活性,可以突破一下这个模型。如上面类隔离的例子,使用同级的类加载器加载相同的类,该类也会互相隔离的。在容器中,我们一般希望容器内,各个应用的代码互相隔离,互不影响,即使这两个应用的代码是完全一样的。
  Tomcat容器的类加载器结构图:
 

猜你喜欢

转载自www.cnblogs.com/guanjianzhuo/p/9119218.html