JVM(3)之双亲委派机制

一、双亲委派机制

1.1概念

JVM类加载器是有亲子层级结构的,如下图:

这里类加载其实就有一个双亲委派机制,加载某个类时会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的类加载路径中查找并载入目标类。

比如我们的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载器加载,扩展类加载器再委托启动类加载器,顶层启动类加载器在自己的类加载路径里找了半天没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器,应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了。

双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载。

1.2为什么要有双亲委派机制

  1. 沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改。
  2. 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性。

        我们思考下为什么要从下线上委托,从上往下加载。设想一下,如果我们是从下往上加载的话,会是多么可怕的一件事情:我们不小心定义了一个java.lang.String类和jdk的String一样的,如果是从下往上加载的话,那么我们自己定义的会优先被加载,那么jdk的String就无法被加载了,那么String中的方法也就无法被调用了,这将是多么可怕的一个事情。

1.3JVM中存在的3个默认的类加载器

  • BootstrapClassLoader:根类加载器:它负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class。

  • ExtClassLoader:展类加载器:它负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。

  • AppClassLoader:应用类加载器:它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH环境变量所指定的JAR包和类路径。

        3个类加载器之间的关系:AppClassLoader的父加载器是ExtClassLoader;,ExtClassLoader的父加载器是BootstrapClassLoader。需要注意的是这里说的父加载器并不是说他们之前存在继承关系,而是在类加载器中有一个parent属性。

1.4类加载过程

        JVM在加载一个类时,会调用AppClassLoader的loadClass方法来加载这个类,不过在这个方法中,会先使用ExtClassLoader的loadClass方法来加载类,同样ExtClassLoader的loadClass方法中会先使用BootstrapClassLoader来加载类,如果BootstrapClassLoader加载到了就直接成功,如果BootstrapClassLoader没有加载到,那么ExtClassLoader就会自己尝试加载该类,如果没有加载到,那么则会由AppClassLoader来加载这个类。

        所以,双亲委派——指得是,JVM在加载类时,会委派给ExtClassLoader和BootstrapClassLoader进行加载,如果没加载到才由自己进行加载。

1.5类加载器源码分析

        public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
            int var3 = var1.lastIndexOf(46);
            if (var3 != -1) {
                SecurityManager var4 = System.getSecurityManager();
                if (var4 != null) {
                    var4.checkPackageAccess(var1.substring(0, var3));
                }
            }

            if (this.ucp.knownToNotExist(var1)) {
                Class var5 = this.findLoadedClass(var1);
                if (var5 != null) {
                    if (var2) {
                        this.resolveClass(var5);
                    }

                    return var5;
                } else {
                    throw new ClassNotFoundException(var1);
                }
            } else {
                return super.loadClass(var1, var2);
            }
        }

        可以看到在loadClass中现在本缓存里面找,如果找不到就委托上级去加载。

1.6那些情况需要打破双亲委派机制

        tomcat打破双亲委派:

  1. tomcat是web容器,一个web容器可以部署多个程序,不同程序依赖的第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一个份,因此要保证好相互的隔离。并且为了安全tomcat容器依赖的类库和应用所以来的类库也需要隔离。这就打破了双亲委派。
  2. 众所周知jsp文件也是最终编译成class文件被夹在到虚拟机的。对于class修改了,如果类名一样类加载器会直接去取内存中已经存在的class,修改就不会生效,tomcat在修改jsp页面不需要重启服务也可以生效。说明也打破了双亲委派机制。tomcat是如何做的呢?他给每个JSP都准备了一个Jsp类加载器。当jsp改变就卸载类加载器,重新创建类加载器,重新加载jsp文件。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值