发布于2021-06-14 09:34 阅读(1002) 评论(0) 点赞(8) 收藏(4)
从宏观角度来看,JVM中实例化一个对象的基本过程如下:
类加载器主要负责将class从本地磁盘加载到内存中,ClassLoader有一种层次关系,但不是传统意义上的继承。层次关系如下:
BootstrapClassLoader用于加载lib目录下的核心库,比如String就由此加载。
ExtClassLoader加载一些拓展类,至于哪些是拓展类,文章的后面会做验证。
AppClassLoader加载classpath下的类。
为啥需要这么多加载器,而且不同的加载器有着不同的管辖范围?这就引出一个概念:”双亲委派机制“
当JVM加载一个类的时候,不会直接使用AppClassLoader,而是交给ExtClassLoader加载,ExtClassLoader加载前也会尝试用BootstrapClassLoader加载。
总的来说,就是保持一个原则:保证高层次的类加载器优先加载。
这是一种典型的特权行为,通过优先级的划分,来使得核心类库优先被加载。
这样核心类库无法被应用程序篡改,保证了JVM环境的安全。
main()方法是Java程序的入口,而Launcher是JRE中用于启动main()方法的类,其内部定义了ExtClassLoader与AppClassLoader,负责初始化工作。
继承体系同AppClassLoader,放在下面说了。
主要的创建逻辑在 createExtClassLoader()
获取ExtClassLoader负责的加载的class文件目录
可以打印一下
- public class ClassLoaderDemo {
-
- public static void main(String[] args) throws ClassNotFoundException {
-
- String bootstrapUrl = System.getProperty("java.ext.dirs");
- String[] split = bootstrapUrl.split(";");
- for (String s : split) {
- System.out.println(s);
- }
- }
- }
结果
可以看出是jre下的 ext包
继承体系
继承自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显得比较神秘一点,它由C++实现,是JVM自身的一部分,我们看不到其具体的实现。
但依然可以通过一些方法 来捕捉它
String的ClassLoader理论上应该是BootstrapClassLoader
但是打印出来却是null。
我们结合ExtClassLoader的构造函数分析
第二个参数传递的是他的 父 ClassLoader(在AppClassLoader小标题下已经分析了,不重复),也传了一个null。
结合起来看,结论就出来了。
BootstrapClassLoader抽象层级较高,并且由C++实现,无法拓展,如果尝试获取某个类的ClassLoader返回值是null,则表示由BootstrapClassLoader加载。
进一步验证
我定义一个UserInfo类用于测试,尝试嵌套调用它的ClassLoader
- public class ClassLoaderDemo {
-
- public static void main(String[] args) throws ClassNotFoundException {
- System.out.println(UserInfo.class.getClassLoader());
- System.out.println(UserInfo.class.getClassLoader().getParent());
- System.out.println(UserInfo.class.getClassLoader().getParent().getParent());
- }
- }
结果中体现的层次关系就很明显了
其实Launcher中有一个变量 sun.boot.class.path 存放的就是BootStrapClassLoader管辖的范围
- public class ClassLoaderDemo {
-
- public static void main(String[] args) throws ClassNotFoundException {
- String property = System.getProperty("sun.boot.class.path");
- for (String s : property.split(";")) {
- System.out.println(s);
- }
- }
- }
控制台输出如下
可见主要是jre lib目录下的一些jar包
由于篇幅原因,自定义ClassLoader、字节码加密等知识总结就不准备放一篇文章里了。
如有错误,欢迎批评指正!
作者:哦哦好吧
链接:http://www.javaheidong.com/blog/article/222688/a84ad1bbacaf1c8eed78/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!