什么是ClassLoader
ClassLoader在Java中有非常重要的作用,它主要工作在Class装载的加载阶段,其主要的作用是从系统外部获得Class二进制数据流。
它是Java的核心组件,所有的class都是由ClassLoader进行加载的,ClassLoader负责将Class文件里的二进制数据装载进系统,然后交给Java虚拟机进行连接,初始化等操作。
ClassLoader种类
名称 | 作用 |
---|---|
启动类加载器(Bootstrap ClassLoader) | C++编写,在java里无法获取,负责加载 |
扩展类加载器(Extension ClassLoader) | Java编写,可以在java里获取,负责加载 |
系统类加载器/应用程序类加载器(Application ClassLoader) | 是与我们接触对多的类加载器,我们写的代码默认就是由它来加载,ClassLoader.getSystemClassLoader返回的就是它。 |
自定义ClassLoader | Java编写,定制化加载 |
ClassLoader的双亲委派机制
Java中任意一个类,都需要由加载它的类加载器和这个类本身来一同确立其在Java虚拟机中的唯一性,判断一个类是否相同,通常用equals()方法,isInstance()方法和isAssignableFrom()方法。来判断,对于同一个类,如果没有采用相同的类加载器来加载,在调用的时候,会产生意想不到的结果;
如果不是同一个类加载器加载,即时是相同的class文件,也会出现判断不想同的情况,从而引发一些意想不到的情况,为了保证相同的class文件,在使用的时候,是相同的对象,jvm设计的时候,采用了双亲委派的方式来加载类,同时也避免多份同样字节码的加载:类似于单例模式,多个ClassLoader只需要加载一个类字节码即可。形成一个整体的一种机制。
如图所示,自下而上查找某个类是否被加载过,首先从CustomClassLoader开始查找(findClass)如果有加载过直接返回,如果没加载过就会委派给AppClassLoader去查找,依次查询。
类的装载过程
双亲委派代码解析
一起看下在java.lang.ClassLoader中的loadClass方法,由递归实现
大体流程:
- 子类先委托父类加载
- 父类加载器有自己的加载范围,范围内没有找到,则不加载,并返回给子类
- 子类在收到父类无法加载的时候,才会自己去加载
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
// 使用指定的<a href="#name">二进制名称</a>加载类,默认实现按以下顺序搜索类
// 1. 调用findLoadedClass()检查类是否已经加载
// 2. 调用父类加载器方法的loadClass。 如果父级为null,则该类使用内置虚拟机的加载程序。
// 3. 调用父类加载器没找到则自己调用findClass(String)方法来找到类
// 如果使用上述步骤找到了该类,并且resolve标志为true,然后此方法将调用生成的Class 对象上的#resolveClass(Class)}方法。
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.(如果还是没有获得该类,调用findClass找到类)
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats (记录JVM数据)
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
// 链接到指定的类,初始化等
if (resolve) {
resolveClass(c);
}
return c;
}
}
破坏双亲委派
待续...