1. 程式人生 > >自定義類載入如何打破雙親委託機制的正確姿勢

自定義類載入如何打破雙親委託機制的正確姿勢

通過自定義類載入打破類載入雙親規則

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    Class<?> clazz = findLoadedClass(name);
    try{
        if(clazz == null) clazz = findClass(name);
    }catch (ClassNotFoundException e){
        // ClassNotFoundException thrown if class not found
// from the non-null parent class loader } if(clazz == null && getParent() != null){ clazz = getParent().loadClass(name); } if(resolve){ resolveClass(clazz); } return clazz; }

  其中clazz = findClass(name);必須catch,儘管loadClass也丟擲了ClassNotFoundException異常,因為我們現在要實現的是,自定義類載入器載入不到(也就是找不到這個類),就讓自定義載入器的父載入器(ApplicationClassLoader)去載入,如果你這裡將異常丟擲了,父載入器根本沒有機會去載入。那麼什麼時候自定載入器載入不到呢,這個問題就在findClass(name)裡,看你是怎麼實現的findClass了。如:

/**
     * 這是查詢非classpath下的類(自定義目錄),並未打破雙親規則
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
//        String className = name.substring(name.lastIndexOf("."));
//        name.substring(0, name.lastIndexOf("."));
String classPath = dir + File.separator + name.replace(".", "\\") + ".class"; // File classFile = new File(dir, classPath); File classFile = new File(classPath); if(!classFile.exists()){ throw new ClassNotFoundException("this class "+ classPath +" is not found under [" + dir + "]"); } byte[] classBytes = loadClassBytes(classFile);//通過class檔案獲取陣列 if(null == classBytes || classBytes.length == 0) throw new ClassNotFoundException("load this class is failed"); //這樣還是載入不到java.*的類,因為在ClassLoader裡面是寫死的 Class c = AccessController.doPrivileged(new PrivilegedAction<Class>() { @Override public Class run() { return defineClass(name, classBytes, 0, classBytes.length); } }); System.out.println("find class successfully"); return c; }

  如上,在自定義目錄(非classpath)下找不到這個你這個類名指定的class檔案,就會丟擲ClassNotFoundException異常,所以像java.*包裡的類,自定義載入器是載入不到的(就算有這個檔案,也載入不到),所以這時就需要父載入器去載入了,ClassNotFoundException也由父載入器去丟擲。注意從父載入器開始,還是滿足雙親委託機制的。

  最後說明一下,其實tomcat類載入機制並未打破類雙親委託機制,它只是沒有classpath的概念,然後載入的類是從自定義目錄裡去載入的,所以才會去實現自定義載入器。