天天看点

JVM双亲委派模型

文章目录

      • 什么是双亲委派模型(Parent Delegation Model)?
        • 双亲委派模型的工作过程?
      • 如何破坏JVM双亲委派模型

什么是双亲委派模型(Parent Delegation Model)?

JVM双亲委派模型
Bootstrap ClassLoader :根类加载器,负责加载 Java 的核心类,它不是 java.lang.ClassLoader 的子类,而是由 JVM 自身实现。

Extension ClassLoader :扩展类加载器,扩展类加载器的加载路径是 JDK 目录下 jre/lib/ext 。扩展加载器的 #getParent() 方法返
回 null ,实际上扩展类加载器的父类加载器是根加载器,只是根加载器并不是 Java 实现的。

System ClassLoader :系统(应用)类加载器,它负责在 JVM 启动时加载来自 Java 命令的 -classpath 选项、java.class.path 系统属
性或 CLASSPATH 环境变量所指定的 jar 包和类路径。程序可以通过 #getSystemClassLoader() 来获取系统类加载器。系统加载器
的加载路径是程序运行的当前路径。

该模型要求除了顶层的 Bootstrap 启动类加载器外,其余的类加载器都应当有自己的父类加载器。子类加载器和父类加载器不是以
继承(Inheritance)的关系来实现,而是通过组合(Composition)关系来复用父加载器的代码。简略代码如下:



每个类加载器都有自己的命名空间(由该加载器及所有父类加载器所加载的类组成。

在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类。

在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类)。

类加载器负责加载所有的类,同一个类(一个类用其全限定类名(包名加类名)标志)只会被加载一次。
           

双亲委派模型的工作过程?

1、当前 ClassLoader 首先从自己已经加载的类中,查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。

每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。

2、当前 ClassLoader 的缓存中没有找到被加载的类的时候

委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到 bootstrap ClassLoader。
当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

           
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
           

如何破坏JVM双亲委派模型

而如果想打破双亲委派模型则需要重写loadClass()方法(当然其中的坑也不会少)。典型的打破双亲委派模型的框架和中间件有tomcat与osgi.