ClassLoader分類
在JVM中,有三個(gè)ClassLoader绞幌,分別是:
BootsTrap ClassLoader,Extension ClassLoader,App ClassLoader.
同樣的屋谭,在Android DVM(ART類似,具體實(shí)現(xiàn)不同)中也有三個(gè)ClassLoader:
BootClassLoader:主要用于加載系統(tǒng)類徊都,包括Java和Android的類庫(kù)
PathClassLoader:主要加載應(yīng)用(DVM已安裝)中的類,它的加載路徑固定广辰,無(wú)法指定
DexClassLoader :可以加載任意路徑的Zip暇矫,Jar,Apk择吊,可以實(shí)現(xiàn)動(dòng)態(tài)加載(熱更新李根,插件化)
PathClassLoader和DexClassLoader的源碼
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 librarySearchPath 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 librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
}
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 librarySearchPath 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 librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
}
可以看到,兩者只有構(gòu)造方法几睛,均無(wú)具體實(shí)現(xiàn)方法房轿。
ClassLoader加載過(guò)程
================
PathClassLoader和DexClassLoader 都繼承BaseDexClassLoader
,先看BaseDexClassLoader
的構(gòu)造方法:
/**
* Constructs an instance.
*
* @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; may be {@code null}
* @param librarySearchPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public BaseDexClassLoader(String dexPath, File optimizedDirectory/*odex目錄*/,
String libraryPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
findClass()
方法:
#BaseDexClassLoader.java
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
//調(diào)用DexPathList.findClass,找到直接返回,找不到直接throw exception
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
這里的pathList是DexPathList實(shí)例:
#DexPathList.java
public Class findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
//找到dex file
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
DexFile.loadClassBinaryName():
#DexFile.java
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, mCookie, suppressed);
}
private static Class defineClass(String name, ClassLoader loader, long cookie,
List<Throwable> suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie);
} catch (NoClassDefFoundError e) {
if (suppressed != null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if (suppressed != null) {
suppressed.add(e);
}
}
return result;
}
//調(diào)用本地方法defineClassNative
private static native Class defineClassNative(String name, ClassLoader loader,
Object cookie, DexFile dexFile)throws ClassNotFoundException, NoClassDefFoundError;
DexFile.defineClassNative()具體實(shí)現(xiàn)請(qǐng)看這里:
art\runtime\native\dalvik_system_DexFile.cc
可以看出枉长,BaseDexClassLoader中有個(gè)pathList對(duì)象冀续,pathList中包含一個(gè)DexFile的數(shù)組dexElements,由上面分析知道必峰,dexPath傳入的原始dex(.apk,.zip,.jar等)文件在optimizedDirectory文件夾中生成相應(yīng)的優(yōu)化后的odex文件洪唐,dexElements數(shù)組就是這些odex文件的集合,如果不分包一般這個(gè)數(shù)組只有一個(gè)Element元素吼蚁,也就只有一個(gè)DexFile文件凭需,而對(duì)于類加載呢问欠,就是遍歷這個(gè)集合,通過(guò)DexFile去尋找粒蜈。最終調(diào)用native方法的defineClass顺献。