Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
知道类加载的过程吗?
类加载过程:加载->连接->初始化。
连接过程又可分三步:验证->准备->解析。
那么加载时这一步又做了什么?
类加载过程的第一步,主要完成下面3件事情:
1、通过全类名获取此类的二进制字节流
2、将字节流所代表的的静态存储结构转换为方法区的运行时数据结构
3、在内存中生成一个代表该类的Class对象,作为方法区这些数据的访问入口。
有哪些类加载器?
JVM中内置了三个重要的ClassLoader,除了BootstrapClassLoader 是用C++语言写的,由其他类加载器均 Java实现且全部继承自java.lang.ClassLoader :
1、BootstrapClassLoader(引导启动类加载器):
嵌在JVM内核中的加载器,是最顶层的加载器,主要负载加载JAVA_HOME/lib下的类库,引导启动类加载器无法被应用程序直接使用。
2、ExtensionClassLoader(扩展类加载器):
主要加载JAVA_HOME/lib/ext目录中的类库。它的父加载器是BootstrapClassLoader
3、App ClassLoader(应用类加载器):
App ClassLoader是应用程序类加载器,负责加载应用程序classpath目录下的所有jar和class文件。它的父加载器为Ext ClassLoader(JKD1.8之后为PlatformClassLoader)
双亲委派模型介绍
每一个类都有对应它的类加载器。系统中的ClassLoader 在协同工作的时候会默认使用双亲委派模型。
即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载过的类会直接返回,否则才会尝试加载。
加载的时候,首先会把该请求委派给该父类加载器的loadClass()处理,因此所有的请求最终都应该会传送到顶层的启动类加载器BootstrapClassLoader中。当父类加载器无法处理时,才由自己来处理。当父类加载器为null,会使用启动类加载器BootstrapClassLoader
每个类加载都有一个父类加载器,我们可以通过程序来验证。
public class ClassLoaderTest {
public static void main(String[] args) {
System.out.println("1、ClassLoaderTest类的加载器" +
ClassLoaderTest.class.getClassLoader());
System.out.println("2、ClassLoaderTest类的父类的加载器" +
ClassLoaderTest.class.getClassLoader().getParent());
System.out.println("3、ClassLoaderTest类的父类的父类的加载器" +
ClassLoaderTest.class.getClassLoader().getParent().getParent());
}
}
AppClassLoader的父类加载器是PlatformClassLoader,而PlatformClassLoader为null,null并不代表PlatformClassLoader没有父类加载器,而是BootstrapClassLoader。
双亲委派模型实现源码分析
双亲委派模型代码集中在java.lang.ClassLoader的loadClass()中,相关代码如下:
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) { //父加载器不为空,调用父加载器loadClass()方法处理
c = parent.loadClass(name, false);
} else { //父加载器为空,使用BootstrapClassLoader加载
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();
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
双亲委派模型带来的好处是:可以避免类的重复加载,保证了Java程序的稳定运行。