天天看點

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.