轉(zhuǎn)載自:最新內(nèi)容及最清晰格式請(qǐng)見(jiàn)http://www.trinea.cn/android/java-loader-common-class/
本文主要介紹 ClassLoader 的基礎(chǔ)知識(shí),ClassLoader 如何動(dòng)態(tài)加載 Jar,ClassLoader 隔離問(wèn)題及如何加載不同 Jar 中的公共類(lèi)。
本文工程開(kāi)源地址見(jiàn):Java Dynamic Load Jar@Github,Clone 以后直接以 Java application去運(yùn)行 java-dynamic-loader-host 工程即可。
其實(shí)本文只是 Android 插件化的一個(gè)引子,做過(guò) Android 插件化的同學(xué),可以試試對(duì)于 Android Support 包中的 FragmentActivity 和 ActionBarActivity 怎么像一般的 Activity 一樣被代理,挺有意思。
1. ClassLoader 的基礎(chǔ)知識(shí)無(wú)論是 JVM 還是 Dalvik 都是通過(guò) ClassLoader 去加載所需要的類(lèi),而 ClassLoader 加載類(lèi)的方式常稱為雙親委托,ClassLoader.java 具體代碼如下:
PRotected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { // Don't want to see this. } if (clazz == null) { clazz = findClass(className); } } return clazz;}
從上面加載類(lèi)的順序中我們可以知道,loadClass 會(huì)先看這個(gè)類(lèi)是不是已經(jīng)被 loaded 過(guò),沒(méi)有的話則去他的 parent 去找,如此遞歸,稱之為雙親委托。
2. 動(dòng)態(tài)加載 JarJava 中動(dòng)態(tài)加載 Jar 比較簡(jiǎn)單,如下:
URL[] urls = new URL[] {new URL("file:libs/jar1.jar")};URLClassLoader loader = new URLClassLoader(urls, parentLoader);表示加載 libs 下面的 jar1.jar,其中 parentLoader 就是上面1中的 parent,可以為當(dāng)前的 ClassLoader。
3. ClassLoader 隔離問(wèn)題大家覺(jué)得一個(gè)運(yùn)行程序中有沒(méi)有可能同時(shí)存在兩個(gè)包名和類(lèi)名完全一致的類(lèi)?JVM 及 Dalvik 對(duì)類(lèi)唯一的識(shí)別是 ClassLoader id + PackageName + ClassName,所以一個(gè)運(yùn)行程序中是有可能存在兩個(gè)包名和類(lèi)名完全一致的類(lèi)的。并且如果這兩個(gè)”類(lèi)”不是由一個(gè) ClassLoader 加載,是無(wú)法將一個(gè)類(lèi)的示例強(qiáng)轉(zhuǎn)為另外一個(gè)類(lèi)的,這就是 ClassLoader 隔離。 如 Android 中碰到如下異常
android.support.v4.view.ViewPager can not be cast to android.support.v4.view.ViewPager
當(dāng)碰到這種問(wèn)題時(shí)可以通過(guò) instance.getClass().getClassLoader(); 得到 ClassLoader,看 ClassLoader 是否一樣。
4. 加載不同 Jar 包中公共類(lèi)現(xiàn)在 Host 工程包含了 common.jar, jar1.jar, jar2.jar,并且 jar1.jar 和 jar2.jar 都包含了 common.jar,我們通過(guò) ClassLoader 將 jar1, jar2 動(dòng)態(tài)加載進(jìn)來(lái),這樣在 Host 中實(shí)際是存在三份 common.jar,如下圖:
我們?cè)趺幢WC common.jar 只有一份而不會(huì)造成上面3中提到的 ClassLoader 隔離的問(wèn)題呢,其實(shí)很簡(jiǎn)單,有三種方式:第一種:我們只要讓加載 jar1 和 jar2 的 ClassLoader 的 parent 為同一個(gè) ClassLoader,并且該 ClassLoader 加載過(guò) common.jar,通過(guò)上面 1 中我們知道根據(jù)雙親委托,最后都會(huì)首先被 parentClassLoader加載。
第二種:我們重寫(xiě) jar1 和 jar2 的 ClassLoader,在 loadClass 函數(shù)中我們先去某個(gè)含有 common.jar 的 ClassLoader 中 load 即可,其實(shí)就是把上面的 parentClassLoader 換掉了而已。
第三種:在生成 jar1 和 jar2 時(shí)把 common.jar 去掉,只保留 host 中一份,以 host ClassLoader 為 parentClassLoader 即可。具體可見(jiàn)代碼:JarClassLoader
大家測(cè)試后會(huì)發(fā)現(xiàn)對(duì)于 Java 是正常的,而方式一和方式二對(duì)于 Android 卻失敗,具體原因下次再說(shuō)吧
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注