Android類加載(二)——雙親委托機(jī)制

Android類加載(一)——DVM、ART、Dexopt、DexAot名詞解析
Android類加載(二)——雙親委托機(jī)制
Android類加載(三)——源碼解讀

Java類加載器

定義
  • BootClassLoader
    用于加載Android FrameWork層的class文件(系統(tǒng)的Activity)
  • PathClassLoader
    用于加載Android應(yīng)用程序的class 文件(自己寫(xiě)的MainActivity)
    也可以加載指定的dex,以及jar、zip、apk中的classes.dex
  • DexClassLoader
    加載指定的dex,以及jar、zip、apk中的classes.dex

比較PathClassLoader和DexClassLoader

  • 在一個(gè)app安裝的過(guò)程中,Android系統(tǒng)是沒(méi)有用到DexClassLoader類的,而PathClassLoader會(huì)被用于加載Android應(yīng)用程序的class 文件(例如自己寫(xiě)的MainActivity),DexClassLoader類就是提供給開(kāi)發(fā)者使用的類,Android FrameWork層并沒(méi)有使用到DexClassLoader。
  • 構(gòu)造方法的區(qū)別
public class DexClassLoader extends BaseDexClassLoader {
    /**
     * Creates a {@code DexClassLoader} that finds interpreted and native
     * code.  Interpreted classes are found in a set of DEX files contained
     * in Jar or APK files.
     *
     * <p>The path lists are separated using the character specified by the
     * {@code path.separator} system property, which defaults to {@code :}.
     *
     * @param dexPath the list of jar/apk files containing classes and
     *     resources, delimited by {@code File.pathSeparator}, which
     *     defaults to {@code ":"} on Android
     * @param optimizedDirectory directory where optimized dex files
     *     should be written; must not be {@code null}
     * @param libraryPath the list of directories containing native
     *     libraries, delimited by {@code File.pathSeparator}; may be
     *     {@code null}
     * @param parent the parent class loader
     */
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}
public class PathClassLoader extends BaseDexClassLoader {
    /**
     * Creates a {@code PathClassLoader} that operates on a given list of files
     * and directories. This method is equivalent to calling
     * {@link #PathClassLoader(String, String, ClassLoader)} with a
     * {@code null} value for the second argument (see description there).
     *
     * @param dexPath the list of jar/apk files containing classes and
     * resources, delimited by {@code File.pathSeparator}, which
     * defaults to {@code ":"} on Android
     * @param parent the parent class loader
     */
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }

    /**
     * Creates a {@code PathClassLoader} that operates on two given
     * lists of files and directories. The entries of the first list
     * should be one of the following:
     *
     * <ul>
     * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
     * well as arbitrary resources.
     * <li>Raw ".dex" files (not inside a zip file).
     * </ul>
     *
     * The entries of the second list should be directories containing
     * native library files.
     *
     * @param dexPath the list of jar/apk files containing classes and
     * resources, delimited by {@code File.pathSeparator}, which
     * defaults to {@code ":"} on Android
     * @param libraryPath the list of directories containing native
     * libraries, delimited by {@code File.pathSeparator}; may be
     * {@code null}
     * @param parent the parent class loader
     */
    public PathClassLoader(String dexPath, String libraryPath,
            ClassLoader parent) {
        super(dexPath, null, libraryPath, parent);
    }
}

從源碼里可以看出它們都派生于BaseDexClassLoader類,但在它們的構(gòu)造方法稍有不同

public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
public PathClassLoader(String dexPath, String libraryPath,
           ClassLoader parent) {
       super(dexPath, null, libraryPath, parent);
   }

有三個(gè)參數(shù)是一樣的

  • dexPath:要加載的dex所在的目錄
  • libraryPath:Native方法so文件所在的目錄
  • parent:可以理解為雙親加載機(jī)制里的所謂的“父親”(雙親委托機(jī)制下面再講)
  • optimizedDirectory:opt優(yōu)化后的dex文件所在的目錄(而且從源碼的注釋里可以看到,這個(gè)目錄必須為私有目錄,不能為sd卡的目錄)

而DexClassLoader就比PathClassLoader多了一個(gè)optimizedDirectory參數(shù),
也就是說(shuō)DexClassLoader用于存儲(chǔ)opt優(yōu)化后的dex文件的保存路徑可以自己定義傳進(jìn)去,而PathClassLoader存儲(chǔ)opt優(yōu)化后的dex文件的保存路徑是系統(tǒng)默認(rèn)的。僅此這個(gè)區(qū)別而已。

雙親委托機(jī)制

類加載在加載類時(shí),首先將加載任務(wù)委托給父類加載器加載,依次遞歸,如果父類加載器可以完成加載任務(wù),就成功返回,如果父類加載器無(wú)法完成或者沒(méi)有父類加載器時(shí),才自己去加載。
簡(jiǎn)單一個(gè)詞語(yǔ)概括:啃老族機(jī)制。

下面我們用一段代碼來(lái)進(jìn)行解釋:


public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //PathClassLoader
        ClassLoader classLoader = this.getClassLoader();
        //BootClassLoader
        ClassLoader classLoader1 = Activity.class.getClassLoader();
        
        System.out.println("PathClassLoader getClassLoader:"+classLoader);
        System.out.println("PathClassLoader getClassLoader 的父親 :"+classLoader.getParent());
        System.out.println("BootClassLoader Activity.class :"+classLoader1);

image.png

從打印中我們可以得出以下結(jié)論

  • MainActivity的類加載器是PathClassLoader
  • Activity的類加載器是PathClassLoader
  • PathClassLoader的父親是BootClassLoader

注意:這里所說(shuō)的父親并不是指這個(gè)類的父類(BaseDexClassLoader),只是ClassLoder類里的一個(gè)類型為ClassLoader的成員變量名稱叫做parent

image.png

image.png
那么為什么要使用雙親委托機(jī)制呢?

在我們應(yīng)用程序啟動(dòng)的時(shí)候,BootClassLader會(huì)去加載FrameWork層的所有的類,例如上面的Activity,而我們自己寫(xiě)的代碼BootClassLader是沒(méi)辦法去加載的,只能由PathClassLoader去加載,因?yàn)槲覀冏约簩?xiě)的代碼的類,在我們的apk里面,不在系統(tǒng)里面,例如上面的MainActivity。但現(xiàn)在我們寫(xiě)的MainActivity是派生于AppCompatActivity的,AppCompatActivity屬于FrameWork層的類,已經(jīng)被BootClassLader加載了,如果我們不使用雙親委托機(jī)制的話,PathClassLoader是不是加載不到FrameWork層的類,那是不是加載不了AppCompatActivity了,而運(yùn)用雙親委托機(jī)制就能很好的讓不同的類加載器去分別執(zhí)行不同層級(jí)的類加載的任務(wù),這樣也是有利于系統(tǒng)的安全性,對(duì)于開(kāi)發(fā)者來(lái)說(shuō)你是無(wú)法知道怎么去加載系統(tǒng)的類的,你永遠(yuǎn)只能加載自己寫(xiě)的類,系統(tǒng)層面的類是不讓你去加載的,只能由父親BootClassLader去加載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容