首页 > 作文

JVM的类加载器和双亲委派模式你了解吗

更新时间:2023-04-06 03:31:29 阅读: 评论:0

类加载器

java虚拟机设计团队有意把类加载阶段中的“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类。实现这个动作的代码被称为“类加载器”(classloader)。

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在java虚拟机中的大闸蟹怎么蒸唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个class文件,被同一个java虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等

名称加载的类说明bootstrap classloader(启动类加载器)java_home/jre/lib无法直接访问extension classloader(拓展类加载器)java_home/jre/lib/ext上级为bootstrap,显示为nullapplication classloader(应用程序类加载器)classpath上级为extension自定义类加载器自定义上级为application

1、启动类加载器

可通过在控制台输入指令,使得类被启动类加器加载,它是用c++写的,看不到源码;其他类加载器是用java写的,说白了就是一些java类,比如扩展类加载器、应用类加载器。

//查询所有被启动类加载器加载的类url[] urls = sun.misc.launcher.getbootstrapclasspath().geturls();for (url url : urls) {    system.out.println(url);}
//查询到的结果file:/c:/program%20files/java/jre1.8.0_131/lib/resources.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/rt.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/sunrsasign.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/js.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/jce.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/charts.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/jfr.jarfile:/c:/program%20files/java/jre1.8.0_131/class

由上可以看出启动类加载的都是jre和jre/lib目录下的核心库,具体路径要看你的jre安装在哪里

2、拓展类加载器

如果classpath和java_home/jre/lib/ext 下有同名类,加载时会使用拓展类加载器加载。当应用程序类加载器发现拓展类加载器已将该同名类加载过了,则不会再次加载

url[] urls = ((urlclassloader) classloader.getsystemclassloader().getparent()).geturls();for (url url : urls) {    system.out.println(url);}
file:/c:/program%20files/java/jre1.8.0_1tan31/lib/ext/access-bridge-64.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/cldrdata.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/dnsns.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/dns_sd.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/jaccess.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/jfxrt.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/localedata.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/nashorn.jarfile:/c:/program%20fil通知格式范文es/java/jre1.8.0_131/lib/ext/sunec.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/sunjce_provider.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/sunmscapi.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/sunpkcs11.jarfile:/c:/program%20files/java/jre1.8.0_131/lib/ext/zipfs.jar

这些类库具体是什么不重要,只需要知道不同的类库可能是被不同的类加载器加载的。

3、应用程序类加载器

url[] urls = ((urlclassloader) classloader.getsystemclassloader()).geturls();for (url url : urls) {    system.out.println(url);}
file:/{项目工程目录}/bin/

这是当前java工程的bin目录,也就是我们自己的java代码编译成的class文件所在。

4、双亲委派模式

双亲委派模式,调用类加载器classloader 的 loadclass 方法时,查找类的规则。

loadclass源码

protected class<?> loadclass(string name, boolean resolve)    throws classnotfoundexception{    synchronized (getclassloadinglock(name)) {        // 首先查找该类是否已经被该类加载器加载过了        class<?> c = findloadedclass(name);        //如果没有被加载过        if (c == null) {            long t0 = system.nanotime();            try {                //看是否被它的上级加载器加载过了 extension的上级是bootstar梵高的坟茔p,但它显示为null                if (parent != null)带有水字的诗句 {                    c = parent.loadclass(name, fal);                } el {                    //看是否被启动类加载器加载过                    c = findbootstrapclassornull(name);                }            } catch (classnotfoundexception e) {                // classnotfoundexception thrown if class not found                // from the non-null parent class loader                //捕获异常,但不做任何处理            }            if (c == null) {                //如果还是没有找到,先让拓展类加载器调用findclass方法去找到该类,如果还是没找到,就抛出异常                //然后让应用类加载器去找classpath下找该类                long t1 = system.nanotime();                c = findclass(name);                // 记录时间                sun.misc.perfcounter.getparentdelegationtime().addtime(t1 - t0);                sun.misc.perfcounter.getfindclasstime().addelapdtimefrom(t1);                sun.misc.perfcounter.getfindclass().increment();            }        }        if (resolve) {            resolveclass(c);        }        return c;    }}

有一个描述类加载器加载类过程的术语:双亲委派模型。然而这是一个很有误导性的术语,它应该叫做单亲委派模型(parent-delegation model)。但是没有办法,大家都已经这样叫了。所谓双亲委派,这个亲就是指classloader里的全局变量parent,也就是父加载器。

双亲委派的具体过程如下:

当一个类加载器接收到类加载任务时,先查缓存里有没有,如果没有,将任务委托给它的父加载器去执行。父加载器也做同样的事情,一层一层往上委托,直到最顶层的启动类加载器为止。如果启动类加载器没有找到所需加载的类,便将此加载任务退回给下一级类加载器去执行,而下一级的类加载器也做同样的事情。如果最底层类加载器仍然没有找到所需要的class文件,则抛出异常。所以是一条线传上再传下,并没有什么“双亲”。

为什么要双亲委派?

:确保类的全局唯一性。

如果你自己写的一个类与核心类库中的类重名,会发现这个类可以被正常编译,但永远无法被加载运行。因为你写的这个类不会被应用类加载器加载,而是被委托到顶层,被启动类加载器在核心类库中找到了。如果没有双亲委托机制来确保类的全局唯一性,谁都可以编写一个java.lang.object类放在classpath下,那应用程序就乱套了。

从安全的角度讲,通过双亲委托机制,java虚拟机总是先从最可信的java核心api查找类型,可以防止不可信的类假扮被信任的类对系统造成危害。

5、自定义类加载器

如果我们自己去实现一个类加载器,基本上就是继承classloader之后重写findclass方法,且在此方法的最后调包defineclass。

5.1、使用场景

想加载非 classpath 随意路径中的类文件通过接口来使用实现,希望解耦时,常用在框架设计这些类希望予以隔离,不同应用的同名类都可以加载,不冲突,常见于 tomcat 容器

5.2、步骤

继承classloader父类要遵从双亲委派机制,重写 findclass 方法不是重写loadclass方法,否则不会走双亲委派机制读取类文件的字节码调用父类的 defineclass 方法来加载类使用者调用该类加载器的 loadclass 方法
protected class<?> findclass(final string name) throws classnotfoundexception {    // 1、安全检查    // 2、根据绝对路径把硬盘上class文件读入内存    byte[] raw = getbytes(name);     // 3、将二进制数据转换成class对象    return defineclass(raw);}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注www.887551.com的更多内容!

本文发布于:2023-04-06 03:31:28,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/b2266793cb204df6b78be28578cc753a.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:JVM的类加载器和双亲委派模式你了解吗.doc

本文 PDF 下载地址:JVM的类加载器和双亲委派模式你了解吗.pdf

标签:加载   双亲   方法   上级
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图