程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

【jdk源码阅读】第四篇:Launcher源码阅读(类加载器相关)

发布于2021-06-14 09:34     阅读(1002)     评论(0)     点赞(8)     收藏(4)


前言

宏观角度来看,JVM中实例化一个对象的基本过程如下:

类加载器主要负责将class从本地磁盘加载到内存中,ClassLoader有一种层次关系,但不是传统意义上的继承。层次关系如下:

双亲委派机制

BootstrapClassLoader用于加载lib目录下的核心库,比如String就由此加载。

ExtClassLoader加载一些拓展类,至于哪些是拓展类,文章的后面会做验证。

AppClassLoader加载classpath下的类。

为啥需要这么多加载器,而且不同的加载器有着不同的管辖范围?这就引出一个概念:”双亲委派机制“

当JVM加载一个类的时候,不会直接使用AppClassLoader,而是交给ExtClassLoader加载,ExtClassLoader加载前也会尝试用BootstrapClassLoader加载。

总的来说,就是保持一个原则:保证高层次的类加载器优先加载。

这是一种典型的特权行为,通过优先级的划分,来使得核心类库优先被加载。

这样核心类库无法被应用程序篡改,保证了JVM环境的安全。

Launcher

main()方法是Java程序的入口,而Launcher是JRE中用于启动main()方法的类,其内部定义了ExtClassLoader与AppClassLoader,负责初始化工作。

ExtClassLoader

继承体系同AppClassLoader,放在下面说了。

主要的创建逻辑在 createExtClassLoader()

获取ExtClassLoader负责的加载的class文件目录

可以打印一下

  1. public class ClassLoaderDemo {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. String bootstrapUrl = System.getProperty("java.ext.dirs");
  4. String[] split = bootstrapUrl.split(";");
  5. for (String s : split) {
  6. System.out.println(s);
  7. }
  8. }
  9. }

结果

可以看出是jre下的 ext包

AppClassLoader

继承体系

继承自URLClassLoader。通常情况下,没有一重继承,就会多一层含义、多一个作用。

SecureClassLoader

大概意思就是,AppClassLoader是根据路径来加载类资源文件的。

/jdk/bin             不以斜杠结尾,就表示加载一个名为bin的jar包

/jdk/bin/            以斜杠结尾,则表示加载这个文件夹里所有的资源。

 

回到AppClassloader类本身,我们在Laucher的构造方法中看到,获取AppClassLoader实力时,会给他传一个ExtClassLoader

仔细看这个构造方法,将var2(也就是ExtClassLoader)传给了父类的构造

父类又继续向上传

直到传到了ClassLoader

保存了下来,也就是说AppClassLoader中有一个变量parent,其值为ExtClassLoader。

 

下面到了最关键的load环节:

在ClassLoader方法内有一个很重要的私有方法,loadClassInternal

虚拟机会调用私有方法loadClassInternal,而loadClassInternal唯一做的事就是调用loadClass方法。

在经过一些类的合法性校验后,调用父类的loadClass加载类文件。ClassLoader类中的loadClass便是”双亲委派机制“的实现。

我们在自定义ClassLoader时候,必须继承ClassLoader类。其次,官方不建议直接重写loadClass方法,为了遵循双亲委派机制,我们应该保留loadClass中的代码,重写findClass方法。

当loadClass发现BootStrapClassLoader和ExtClassLoader无法加载类时,会调用findClass方法。

BootstrapClassLoader

BootstrapClassLoader显得比较神秘一点,它由C++实现,是JVM自身的一部分,我们看不到其具体的实现。

但依然可以通过一些方法 来捕捉它

String的ClassLoader理论上应该是BootstrapClassLoader

但是打印出来却是null。

我们结合ExtClassLoader的构造函数分析

第二个参数传递的是他的 父 ClassLoader(在AppClassLoader小标题下已经分析了,不重复),也传了一个null。

结合起来看,结论就出来了。

BootstrapClassLoader抽象层级较高,并且由C++实现,无法拓展,如果尝试获取某个类的ClassLoader返回值是null,则表示由BootstrapClassLoader加载。

进一步验证

我定义一个UserInfo类用于测试,尝试嵌套调用它的ClassLoader

  1. public class ClassLoaderDemo {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. System.out.println(UserInfo.class.getClassLoader());
  4. System.out.println(UserInfo.class.getClassLoader().getParent());
  5. System.out.println(UserInfo.class.getClassLoader().getParent().getParent());
  6. }
  7. }

结果中体现的层次关系就很明显了

 

其实Launcher中有一个变量   sun.boot.class.path 存放的就是BootStrapClassLoader管辖的范围

  1. public class ClassLoaderDemo {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. String property = System.getProperty("sun.boot.class.path");
  4. for (String s : property.split(";")) {
  5. System.out.println(s);
  6. }
  7. }
  8. }

控制台输出如下

可见主要是jre   lib目录下的一些jar包

其他

由于篇幅原因,自定义ClassLoader、字节码加密等知识总结就不准备放一篇文章里了。

 

如有错误,欢迎批评指正!

 



所属网站分类: 技术文章 > 博客

作者:哦哦好吧

链接:http://www.javaheidong.com/blog/article/222688/a84ad1bbacaf1c8eed78/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

8 0
收藏该文
已收藏

评论内容:(最多支持255个字符)