Java类加载器及双亲委派

文章对应java8

Java中类加载器有以下三种:
1、启动类加载器(根类加载器Bootstrap ClassLoader)
2、扩展类加载器(ExtClassLoader)
3、应用类加载器(AppClassLoader)

各加载器负责加载的类:
Bootstrap ClassLoader:负责加载JAVA_HOME下lib目录下的类
ExtClassLoader:负责加载JAVA_HOME下lib\ext目录下的类
AppClassLoader:负责加载用户类路径所指定的类库中的类

各加载器实现:
启动类加载器:从名字上看就能确定这不是一个java类,事实上底层是由C++实现的,所以启动类加载器在java程序中无法直接引用。
扩展类加载器:由sun.misc.Launcher$ExtClassLoader实现
应用类加载器:由sun.misc.Launcher$AppClassLoader实现,可由ClassLoader中的getSystemClassLoader方法返回,所以也叫系统类加载器,在java类未指定加载器时的默认加载器,也是典型的用于启动应用的类加载器

加载器怎么产生:
从上边实现上我们可以看出,对于启动类加载器,是由非Java的底层代码在JVM启动时生成的。对于扩展类和应用类,都是通过sun.misc.Launcher类来生成。

public Launcher() {
  ...
  var1 = Launcher.ExtClassLoader.getExtClassLoader();
  ...
  this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
  ...
  Thread.currentThread().setContextClassLoader(this.loader);
  ...
}

双亲委派

具体来讲,就是类加载器在收到一个类的加载请求时,会先委托给父类加载器加载,依次递归,如果父类无法完成加载,子类加载器才会尝试加载。通俗的说,儿子懒,有事了先让父亲做,父亲做不了自己才做。

我们主要应该看看为什么要这样?

在前边的文章中也提到过自定义类加载器,为什么会需要自定义类加载器?因为有的类可能需要通过网络传输、加密、编解码等操作,在这样的情况下就必须使用自定义类加载器来完成加载任务。

然后我们再看看这和双亲委派有什么关系?
设想一下,如果不是这样一种双亲委派的关系,那么核心类库JAVA_HOME下lib目录下的类由启动类加载器加载,如果我们自己也写了一个java.lang.System类,这个类会被系统类进行加载,这造成了什么?
1、重复加载(核心类库中的System已加载)
2、核心类API被破坏,虚拟机安全无法保证

然后我们可以总结出如下结论:
如果使用双亲委派加载机制,就能够确保类加载器和类(全限定名)一起构成了一种类似带有优先级的层次关系
1)被加载之后就不会再被重复加载
2)确保核心类库中相应的API不会被篡改,核心功能及JVM安全能够得到保证
即使你从网络或者其他地方传来一个java.lang.System类,虚拟机通过双亲委派机制发现其加载类为启动类,并已被加载,就不再触发加载动作

上下文类加载器

其作用就是用于类的逆向访问而提出的一种概念,本质上还是应用类加载器。(类的逆向访问的典型例子就是JDBC加载,父类加载器加载的类需要访问子类加载器加载的类)

发布了95 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43878293/article/details/104492452