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

版权声明:文章出自http://www.guanjianzhuo.com/ - 欢迎访问、评论、留言! https://blog.csdn.net/guanjianzhuo/article/details/80534047

一、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容器的类加载器结构图:

 

猜你喜欢

转载自blog.csdn.net/guanjianzhuo/article/details/80534047