深入理解ClassLoader
是什么?
相信大家在准备面试的时候都会背过Java的类加载机制,双亲委派模型。
就是当JVM收到一个类加载请求的时候,当前的类加载器首先会将类加载器传递给它的父类,父类尝试加载,如果失败继续向上传递,如果所有的父类都无法加载,则当前类加载器自己处理。
那这段话理解起来还是比较容易的,但是具体是如何做的呢?下面进行分析。
为什么?
那为什么要使用双亲委派模型吗?当前类加载器自己处理不行吗?
如果我们自己写了一个java.lang.Object类的话,那当前的类加载器直接选择加载的话,那加载的类中就会有两个一样的Object类。应用程序将会变的非常混乱。
怎么做?
下面从源码开始看Java是如何进行类加载的。
ClassLoader
介绍
先进入ClassLoader类中public abstract class ClassLoader, 可以先看一下doc,介绍了ClassLoader这个类,
A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a “class file” of that name from a file system.
大意就是说"一个class loader是一个负责加载class的对象。ClassLoader是一个抽象类。给定一个类的二进制名称,一个class loader应该试图去定位或者生成构成类定义的数据。一个典型的策略是转换类名称为文件名称,然后从文件系统上读取一个叫这个名字的class文件"。
整体还是比较明了的,就是为了加载class的,并且也说了典型的做法就是去文件系统去加载同名的class文件。
在 doc 中还说了,ClassLoader 是支持并行的,后面遗弃看一下是如何支持的。
Class loaders that support concurrent loading of classes are known as parallel capable class
还有就是ClassLoader的分类,在doc中一共分为了三类:
- Bootstrap class loader: 启动类加载器,涉及虚拟机的,比较典型的是null
- Platform class loader: jdk相关的class
- System class loader: 也叫application class loader,platform class loader是它的祖先,一般是加载应用classpath的class
流程
整个类中最重要的就是loadClass()方法了,咱们来逐行解析。
|
|
-
方法的入参为
name和resolve,name刚刚在介绍里面已经说了,就是通过类名称去加载类的;那resolve标志如果为true,则找到类后需要去处理类,这里的处理doc上写的是Links the specified class.,link在这里就是类加载过程中的第二阶段,链接,这一阶段就是验证、准备和解析类。 -
synchronized (getClassLoadingLock(name))第一行是一个同步块,
|
|
从上面有关getClassLoadingLock的代码里面可以看到:
+ getClassLoadingLock(className),判断parallelLockMap是否为null,如果不为null,则获取一个锁对象
+ parallelLockMap在ClassLoader的构造器里被初始化
+ ParallelLoaders有一个register方法,register(Class<? extends ClassLoader> c)用来注册可并行的ClassLoader
+ 如果当前的ClassLoader在ParallelLoaders中注册了,则说明该类支持并行,初始化的时候创建一个ConcurrentHashMap
+ 回到第一点,如果parallelLockMap不为null,说明当前类加载器支持并行,加锁
总的来说,就是判断当前类加载器是否支持并行,如果支持,上锁,不支持,返回本类。
-
Class<?> c = findLoadedClass(name);检查当前类是否已经加载过,一个native的方法去执行 -
下面的流程就是委派流程了,如果父类不为
null,先让父类去loadClass,否则让启动类去load,如果还没找到就由本类去findClass(name),这个就是由类加载器自己去实现了。