JVM类加载器-双亲委派机制,以及破坏方式

JVM字节码加载过程-双亲委派机制:

类文件(磁盘,网络,jar包,war包等等中的JVM字节码文件)被类加载器(类加载器子系统)加载到JVM运行时数据区的方法区(HotSpot虚拟机专有,永久代和元空间(本地内存)是方法区实现的两种方式),并生成对应的Class对象(堆区)。也就是说类信息被加载到方法区,又在堆内存中生成其对应的Class对象做为访问类信息的接口。

不同的类加载器加载路径是不一样的

  • 用户自定义的类是由应用程序类加载器AppClassLoader加载的,加载路径是classpath。
  • 扩展类加载器的加载路径是$JAVA_HOME/jre/lib/ext,只能加载该路径下的类。
  • 引导类加载器加载java的核心类,其加载路径为$JAVA_HOME/jre/lib/rt.jar, resources.jar或者sun.boot.class.path路径下的内容,

    出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

我们知道java.lang.String类作为一个核心类(路径$JAVA_HOME/jre/lib/rt.jar),是由启动类加载器负责加载的,如果我们在工程中自定义一个java.lang.String类,并且使用它,那么我们用的是核心类中的String还是我们自定义的String呢?

然后测试一下这个类会否被加载

执行结果如下:

没有打印自定义String类中的静态代码块的打印信息,这说明没有加载我们自定义的类,这是为什么呢? 加载器AppClassLoader没有加载吗?这就跟JVM类加载器子系统的双亲委派机制有关系了。

双亲委派加载流程:

首先要交给AppClassLoader去加载,但是它会把这个任务委派给其parent加载器(AppClassLoader类中parent引用所指向的类加载器)去加载,一步一步向上委托,最后委托到BootStrapClassLoader。

BootStrapClassLoader会去核心类路径$JAVA_HOME/jre/lib/中加载java.lang.String,发现路径中有这个类,那么就将其加载到内存中,并且到此为止,别的类加载不会再尝试加载这个类。

这样我们自己定义的java.lang.String类就不会被加载了,这种双亲委派加载机制有什么好处呢?

  • 防止重复加载,父加载器加载之后,子加载器不会再重新加载
  • 保证安全,防止我们使用的类(比如String核心类)被替换(比如被网络上下载的相同包名类名类替换),造成风险。

双亲委派机制三种破坏方式:

1.JDK1.2以前没有双亲委派机制

2. SPI(service provider interface): JDBC、JDNI等已经加入java核心库,但是需要用户自己去实现部分接口或者抽象类的情况下,用户自己的实现类也需要被引导类加载器加载,但是这是不可能的( 因为JDBC的实现类不在引导类加载器的加载路径中。),只能委派给线程上下文类加载器去加载,这就打破了双亲加载机制。注意:线程上下文类加载器默认调用系统类加载器去加载

3.为了满足动态代码,比如代码热替换,模块热加载,比如OSGI规范的模块热加载,就打破了双亲委派机制,多个模块内的自定义类加载器之间是平行的。

沙箱安全机制:

沙箱安全机制的理念都是类似的,例如360安全卫士的沙箱安全机制,在沙箱安全环境中,测试一个不知是否安全的程序,防止未知访问系统资源并做出破坏。只是具体的实现不同而已。

JDK1.0时期的实现:

JDK1.1时期的实现:

JDK 1.2时期的实现:

再次改进了安全机制,增加了代码签名,不论本地代码或者远程代码,都会按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间,实现差异化的代码执行权限控制,如下图所示:

JDK1.6时期的实现:

参考尚硅谷,宋红康老师的教程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值