破環雙親委託機制

在這裏插入圖片描述

前言

在之前我們給出的方案都是繞過應用加載器的方式,並沒有避免一層一層的委託,那麼有沒有什麼辦法可以繞過這種雙親委託模型呢?

很慶幸,JDK提供的雙親委託機制並非是一個強制的模型,程序員可以對其進行靈活的發揮破環這種委託機制的,比如說熱部署,其實就是不停止服務的情況下,更新JVM中的代碼。

具體實現

以下是具體的實現,繼承上篇文章中的MyClassLoader,重寫loadClass方法。

public class BrokerDelegateClassLoader extends MyClassloader {
    
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        //1
        synchronized (getClassLoadingLock(name)) {
            //2
            Class<?> clazz = findLoadedClass(name);
            //3
            if (clazz == null) {
                //4
                if (name.startsWith("java.") || name.startsWith("javax")) {
                    try {
                        clazz = getSystemClassLoader().loadClass(name);
                    } catch (Exception e) {
                        //ignore
                    }
                }
            } else {
                //5
                try {
                    clazz = this.findClass(name);
                } catch (ClassNotFoundException e) {
                    //ignore
                }
                //6
                if (clazz == null) {
                    if (getParent() != null) {
                        clazz = getParent().loadClass(name);
                    } else {
                        clazz = getSystemClassLoader().loadClass(name);
                    }
                }
            }
            if (null == clazz) {
                throw new ClassNotFoundException("The class " + name + " not fount.");
            }
            if (resolve) {
                resolveClass(clazz);
            }
            return clazz;
        }
    }
}


  1. 根據類的全路徑名稱進行加鎖,確保每一個類在多線程情況下只被加載一次
  2. 到已加載類的緩存中查看該類是否已經被加載,如果已加載則直接返回。
  3. 同4
  4. 若緩存中沒有被加載的類,則需要對其進行首次加載,如果以java和javax開頭的,則直接委託給系統類加載器加載。
  5. 如果類不是以java和javax開頭的,嘗試用自己的類加載器進行加載。
  6. 若自定義的加載器沒有完成對類的加載,則委託給父類加載器或者系統類加載器進行加載。
  7. 經過若干次嘗試後,如果還是無法對類進行加載,則拋出無法找到類的異常。

測試代碼


public class BrokerDelegateClassLoader extends MyClassloader {

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        //1
        synchronized (getClassLoadingLock(name)) {
            //2
            Class<?> clazz = findLoadedClass(name);
            //3
            if (clazz == null) {
                //4
                if (name.startsWith("java.") || name.startsWith("javax")) {
                    try {
                        clazz = getSystemClassLoader().loadClass(name);
                    } catch (Exception e) {
                        //ignore
                    }
                } else {
                    //5
                    try {
                        clazz = this.findClass(name);
                    } catch (ClassNotFoundException e) {
                        //ignore
                    }
                    //6
                    if (clazz == null) {
                        if (getParent() != null) {
                            clazz = getParent().loadClass(name);
                        } else {
                            clazz = getSystemClassLoader().loadClass(name);
                        }
                    }
                }
            }
            if (null == clazz) {
                throw new ClassNotFoundException("The class " + name + " not found.");
            }
            if (resolve) {
                resolveClass(clazz);
            }
            return clazz;
        }
    }
}

在這裏插入圖片描述

可以看到仍然是我們自定義類加載器加載的,既然我們可以通過這種打破雙親委託機制進行類加載,那我們自定義的類加載器能否加載一個和String類全路徑名稱完全一致的class呢?請關注下篇博客。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章