詳細(xì)可以查看這篇博客: https://blog.csdn.net/itachi85/article/details/78088701
重點(diǎn)內(nèi)容
雙親委托模式
類加載器查找Class所采用的是雙親委托模式,所謂雙親委托模式就是首先判斷該Class是否已經(jīng)加載,如果沒有則不是自身去查找而是委托給父加載器進(jìn)行查找,這樣依次的進(jìn)行遞歸,直到委托到最頂層的Bootstrap ClassLoader,如果Bootstrap ClassLoader找到了該Class,就會直接返回,如果沒找到,則繼續(xù)依次向下查找,如果還沒找到則最后會交由自身去查找。
這樣講可能會有些抽象,來看下面的圖。

我們知道類加載子系統(tǒng)用來查找和加載Class文件到 Java 虛擬機(jī)中,假設(shè)我們要加載一個(gè)位于D盤的Class文件,這時(shí)系統(tǒng)所提供的類加載器不能滿足條件,這時(shí)就需要我們自定義類加載器繼承自java.lang.ClassLoader,并復(fù)寫它的findClass方法。加載D盤的Class文件步驟如下:
- 自定義類加載器首先從緩存中要查找Class文件是否已經(jīng)加載,如果已經(jīng)加載就返回該Class,如果沒加載則委托給父加載器也就是App ClassLoader。
- 按照上圖中紅色虛線的方向遞歸步驟1。
- 一直委托到Bootstrap ClassLoader,如果Bootstrap ClassLoader在緩存中還沒有查找到Class文件,則在自己的規(guī)定路徑$JAVA_HOME/jre/libr中或者-Xbootclasspath選項(xiàng)指定路徑的jar包中進(jìn)行查找,如果找到則返回該Class,如果沒有則交給子加載器Extensions ClassLoader。
- Extensions ClassLoader查找$JAVA_HOME/jre/lib/ext目錄下或者-Djava.ext.dirs選項(xiàng)指定目錄下的jar包,如果找到就返回,找不到則交給App ClassLoader。
- App ClassLoade查找Classpath目錄下或者-Djava.ext.dirs選項(xiàng)所指定的目錄下的jar包和Class文件,如果找到就返回,找不到交給我們自定義的類加載器,如果還找不到則拋出異常。
總的來說就是Class文件加載到類加載子系統(tǒng)后,先沿著圖中紅色虛線的方向自下而上進(jìn)行委托,再沿著黑色虛線的方向自上而下進(jìn)行查找,整個(gè)過程就是先上后下。
類加載的步驟在JDK8的源碼中也得到了體現(xiàn),來查看抽象類的ClassLoader方法,如下所示。
源碼
protected Class<?> More ...loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);//1
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);//2
} else {
c = findBootstrapClassOrNull(name);//3
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);//4
// 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;
}
}
雙親委托模式的好處
采取雙親委托模式主要有兩點(diǎn)好處:
- 避免重復(fù)加載,如果已經(jīng)加載過一次Class,就不需要再次加載,而是先從緩存中直接讀取。
- 更加安全,如果不使用雙親委托模式,就可以自定義一個(gè)String類來替代系統(tǒng)的String類,這顯然會造成安全隱患,采用雙親委托模式會使得系統(tǒng)的String類在Java虛擬機(jī)啟動時(shí)就被加載,也就無法自定義String類來替代系統(tǒng)的String類,除非我們修改類加載器搜索類的默認(rèn)算法。還有一點(diǎn), 只有兩個(gè)類名一致并且被同一個(gè)類加載器加載的類,Java虛擬機(jī)才會認(rèn)為它們是同一個(gè)類,想要騙過Java虛擬機(jī)顯然不會那么容易。
replugin 框架classloader的簡單理解
replugin 簡介
replugin-host-gradle
replugin-host-gradle 負(fù)責(zé)在主程序的編譯期中生產(chǎn)各類文件,例如:生成HostBuildConfig類,方便插件框架讀取并自定義其屬性,如:進(jìn)程數(shù)、各類型占位坑的數(shù)量、是否使用AppCompat庫、Host版本、pulgins-builtin.json文件名、內(nèi)置插件文件名等。
自動生成帶 RePlugin 插件坑位的 AndroidManifest.xml文件,文件中帶有如:
<activity
android:theme="@style/Theme.AppCompat"
android:name="com.qihoo360.replugin.sample.host.loader.a.ActivityN1STTS0" //這個(gè)就是坑位了
android:exported="false"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
/>
replugin-host-library
對應(yīng)com.qihoo360.replugin:replugin-host-lib:xxx依賴,是一個(gè)Java工程,由主程序負(fù)責(zé)引入,是RePlugin的核心工程,負(fù)責(zé)初始化、加載、啟動、管理插件等
replugin-plugin-gradle
對應(yīng)com.qihoo360.replugin:replugin-plugin-gradle:xxx ,是一個(gè)Gradle插件,由插件負(fù)責(zé)引入,主要負(fù)責(zé)在插件的編譯期中:配置插件打包相關(guān)信息;動態(tài)替換插件工程中的繼承基類,如下,修改Activity的繼承、Provider的重定向等。
/* LoaderActivity 替換規(guī)則 */
def private static loaderActivityRules = [
'android.app.Activity' : 'com.qihoo360.replugin.loader.a.PluginActivity',
'android.app.TabActivity' : 'com.qihoo360.replugin.loader.a.PluginTabActivity',
'android.app.ListActivity' : 'com.qihoo360.replugin.loader.a.PluginListActivity',
'android.app.ActivityGroup' : 'com.qihoo360.replugin.loader.a.PluginActivityGroup',
'android.support.v4.app.FragmentActivity' : 'com.qihoo360.replugin.loader.a.PluginFragmentActivity',
'android.support.v7.app.AppCompatActivity': 'com.qihoo360.replugin.loader.a.PluginAppCompatActivity',
'android.preference.PreferenceActivity' : 'com.qihoo360.replugin.loader.a.PluginPreferenceActivity',
'android.app.ExpandableListActivity' : 'com.qihoo360.replugin.loader.a.PluginExpandableListActivity'
]
replugin-plugin-library
對應(yīng)com.qihoo360.replugin:replugin-plugin-lib:xxx依賴,是一個(gè)Java工程,由插件端負(fù)責(zé)引入,主要提供通過“Java反射”來調(diào)用主程序中RePlugin Host Library的相關(guān)接口,并提供“雙向通信”的能力,以及各種基類Activity等
其中的RePlugin、RePluginInternal、PluginServiceClient都是反射宿主App :replugin-host-library 中的 RePlugin 、 RePluginInternal 、PluginServiceClient 類方法。
Replugin的ClassLoader
這里主要介紹,宿主和插件使用的ClassLoader,以及它們的創(chuàng)建和Hook住時(shí)機(jī)。這是RePlugin唯一的Hook點(diǎn),而其中插件ClassLoader和宿主ClassLoader是相互關(guān)系的,如下圖
-
宿主的ClassLoader
RePluginClassLoader,宿主的ClassLoader,繼承 PathClassLoader,構(gòu)造方法使用原ClassLoader,和原ClassLoader的Parent生成。其中ParentLoader是因?yàn)殡p親代理模型,創(chuàng)建ClassLoader所需,而原Loader用于保留在后期使用,如下圖
image
如下兩圖,RePluginClassLoader 在創(chuàng)建時(shí),淺拷貝原Loader的資源到 RePluginClassLoader 中,用于欺騙系統(tǒng)還處于原Loader,并且從原Loader中反射出常用方法,用于重載方法中使用
image
宿主Loader中,主要是重載了 loadClass,其中從 PMF(RePlugin中公開接口類)中查找class,如果存在即返回插件class,如果不存在就從原Loader中加載。從而實(shí)現(xiàn)了對加載類的攔截。
這里的 PMF 在加載class時(shí),其實(shí)用的是下面【2、插件的ClassLoader 】:PluginDexClassLoader,這個(gè)后面流程會講到。
-
插件的ClassLoader
PluginDexClassLoader,繼承DexClassLoader,構(gòu)造時(shí)持有了宿主的ClassLoader,從宿主ClassLoader中反射獲取loadClass方法,當(dāng)自己的loadClass方法找不到類時(shí),從宿主Loader中加載。
image
其它內(nèi)容詳細(xì)查看 : http://www.itdecent.cn/p/18530be5dcdd