Java_ClassLoader(ClassLoader / 自定义ClassLoader / DexClassLoader)
本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.youkuaiyun.com/rozol/article/details/77758194
ClassLoader 用来动态加载class文件到内存中使用的
ClassLoader 使用双亲委托模型
来搜索类的
ClassLoader 在Android中有两个子类来加载.dex文件, 分别是 DexClassLoader / PathClassLoader
DexClassLoader 可以加载 jar / apk(未安装/已安装) / dex
PathClassLoader 只可以加载 系统中已安装的apk
原理
/**
* ClassLoader
* ClassLoader用来动态加载class文件到内存中使用的;
* JVM并不会一次性加载程序的所有class文件, 而是根据所需加载.
*
*
* Java内置的ClassLoader
* BootStrap ClassLoader 启动类加载器 (c++编写, 嵌于JVM内核), 负责加载jdk的核心库类 (@Code = printBootStrapClassPath())
* Extension ClassLoader 扩展类加载器 (Java编写, 继承于ClassLoader), 负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar (@Code = printExtensionClassPath())
* App ClassLoader 应用程序(系统)类加载器 (Java编写, 继承于ClassLoader), 负责加载应用程序classpath目录下的所有jar和class文件 (@Code = printAppClassPath())
*
*
* ClassLoader原理 (@Code = classLoaderMod())
* 使用 `双亲委托模型` 来搜索类
* 每个ClassLoader都有一个父类加载器的引用, 如下所示, BootStrap ClassLoader 没有父类加载器, 可作为其他ClassLoader的父类加载器
*
* 启动类加载器 (BootStrap ClassLoader)
* ↑
* 扩展类加载器 (Extension ClassLoader)
* ↑
* 应用程序(系统)类加载器 (App ClassLoader)
* ↑
* 自定义类加载器 (<? extend ClassLoader>)
*
* 当ClassLoader需要加载某个类时, 从 BootStrap ClassLoader 开始检索, 如果没有找到则从Extension ClassLoader 检索, 同理依次传递, 如果都没有, 则麻烦委托者自己从文件或网络检索, 还是没有则抛 ClassNotFoundException 异常.
* 如果某个类加载器找到该类文件, 则将其生成类的定义, 加载到内存当中, 返回实例对象.
* 如果该类已经存在缓存中, 类加载器将不再去检索, 而是将缓存中的类返回.
*
* 该模式的好处: 从上到下依次检索, 避免了 恶意代码冒充系统类代码 安全隐患;
* 因为类加载器只要从自家的类加载中检索到所需的系统代码, 就不会执行用户写的类加载器, 从而避免被调包
*
*
* 判断两个类是否相同?
* 如果两个类的 全类名 相同, 且被同一个类加载器加载的, 即为同一个class;
* 如果两个类的 全类名 相同, 但被非同一个类加载器加载的, 即为非同一个class.
*
* @author Luzhuo
*/
public class Test{
public static void main(String[] args) throws ClassNotFoundException, Exception {
// 输出 BootStrap ClassLoader 加载的文件路径
printBootStrapClassPath();
// 输出 Extension ClassLoader 加载的文件路径
printExtensionClassPath();
// 输出 App ClassLoader 加载的文件路径
printAppClassPath();
// 双亲委托模型
classLoaderMod();
}
/**
* 输出BootStrap ClassLoader 加载的文件路径
*/
private static void printBootStrapClassPath(){
// 方式1: 源码中的文件
final String bootClassPath = System.getProperty("sun.boot.class.path");
System.out.println("BootStrap ClassLoader - path: " + bootClassPath);
// 方式2: 类提供的方法
URL[] urls = Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
}
/**
* 输出 Extension ClassLoader 加载的文件路径
*/
private static void printExtensionClassPath(){
final String extensionClassPath = System.getProperty("java.ext.dirs");
System.out.println("Extension ClassLoader - path: " + extensionClassPath);
}
/**
* 输出 App ClassLoader 加载的文件路径
*/
private static void printAppClassPath(){
final String appClassPath = System.getProperty("java.class.path");
System.out.println("App ClassLoader - path: " + appClassPath);
}
/**
* 双亲委托模型
* ClassLoader原理 (Code = classLoaderMod())
*/
private static void classLoaderMod(){
ClassLoader loader = Test.class.getClassLoader();
while(loader != null) {
System.out.println("classLoaderMod: " + loader);
loader = loader.getParent(); // 获取父类加载器
}
// classLoaderMod: sun.misc.Launcher$AppClassLoader@73d16e93
// classLoaderMod: sun.misc.Launcher$ExtClassLoader@15db9742
// BootStrap ClassLoader 为C++所写, 故未打印
}
}
源码
双亲委托模型
public abstract class ClassLoader {
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// ↓↓↓
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
// ↓↓↓
c = parent.loadClass(name, false);
} else {
// ↓↓↓
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();