Java代码首先要编译成class文件字节码,在运行时通过JIT(即时编译器)编译成本地机器码,最后由ClassLoader将其加载解析成Class对象到内存中。通过ClassLoader的loadClass方法的源码加深对Java类加载机制的理解。
Java的类加载遵循父类优先的原则,也就是说ClassLoader是一个有层级的树形组合体系,并且一个ClassLoader要加载一个类,首先逐层向上检查是否有加载器加载过该类,如果有,将结果逐层返回到下级。如果没有,继续检查直到有一层ClassLoader返回没有加载并且它不应该加载,那么该层的下一层就可以加载该类。
PS:父类优先的方式也不是万能的,在JavaEE Web应用程序中,也会使用子女优先加载的方式;
BootstrapClassLoader:加载JVM自身需要的类,注意在Hotspot JVM中它严格来说不是JVM类加载体系中的,它并不遵循上述机制,也不是下面ExtClassLoader的父类加载器;
ExtClassLoader:加载特定的类:System.getProperty("java.ext.dirs");也就是JRE/LIB/EXT目录下的类,加载的是sun公司的一些扩展包,它是AppClassLoader的父类加载器;
AppClassLoader:加载System.getProperty("java.class.path");就是classpath,看到这个你可能已经知道eclipse项目下.classpath的作用了,就是告诉AppClassLoader这些类由它加载;
继承自URLClassLoader的自定义类加载器,通过调用getSystemClassLoader获取自己的父加载器(AppClassLoader);
ClassLoader的类层次结构:
图中的AppClassLoader和ExtClassLoader是Launcher的内部类;
到现在,我们可以也可以看出Java的ClassLoader使用了职责链设计模式,父优先加载,一定程度上保证了程序安全(防止恶意代码替换JSE核心类)。
一是隐式加载:继承或引用某个类时,有JVM负责加载;
二是显式加载:在代码中调用loadClass(),Class.forName,ClassLoader的findClass方法等,显式加载中也可能包含隐式加载;
findClass:主要由URLClassLoader实现,根据URLClassPath去指定地方查找class文件;取得要加载class文件的字节流;
resolveClass:对Class对象进行Link,载入引用类(超类,接口字段,方法签名,方法中的本地变量);
loadClass:采用默认的加载逻辑根据类名加载一个类,返回Class对象,调用前面3个方法实现;
protected Class> findClass(final String name)
throws ClassNotFoundException
{
final Class> result;
try {
//获取特权,确保有权限可以读取到资源,这里
result = AccessController.doPrivileged(
new PrivilegedExceptionAction>() {
public Class> run() throws ClassNotFoundException {
//将完整的类名转换成文件路径格式
String path = name.replace('.', '/').concat(".class");
//在指定的URLPath中获取对应的class文件资源
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
//获取成功将资源传入,最终获取未解析的Class对象
return defineClass(name, res);
} catch (IOException e) {
//不能成功读取文件内容
throw new ClassNotFoundException(name, e);
}
} else {
//不能获取资源
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
//因为要在特权操作中抛出ClassNotFoundException,使用了PrivilegedExceptionAction回调
//它会将异常包装,这里要解除包装
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
private Class> defineClass(String name, Resource res) throws IOException {
long t0 = System.nanoTime();
int i = name.lastIndexOf('.');
URL url = res.getCodeSourceURL();
//首先加载包
if (i != -1) {
String pkgname = name.substring(0, i);
// Check if package already loaded.
Manifest man = res.getManifest();
definePackageInternal(pkgname, man, url);
}
// Now read the class bytes and define the class
//使用nio,获取字节缓冲区
java.nio.ByteBuffer bb = res.getByteBuffer();
if (bb != null) {
// Use (direct) ByteBuffer:
CodeSigner[] signers = res.getCodeSigners();
CodeSource cs = new CodeSource(url, signers);
sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
return defineClass(name, bb, cs);
} else {
//获取不到缓冲区,直接InputStream获取字节数组
byte[] b = res.getBytes();
// must read certificates AFTER reading bytes.
CodeSigner[] signers = res.getCodeSigners();
CodeSource cs = new CodeSource(url, signers);
sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
return defineClass(name, b, 0, b.length, cs);
}
}
protected final Class> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
//首先检查类名;阻止加载“java.”开头包内的类(应有BootStrapLoader加载);
//确保同一个包内的Class拥有相同的证书
protectionDomain = preDefineClass(name, protectionDomain);
//根据CodeSource获取一个URL的字符串表示
String source = defineClassSourceLocation(protectionDomain);
//字节码验证;类准备(准备字段,方法,实现接口所必需的数据结构);
Class> c = defineClass1(name, b, off, len, protectionDomain, source);
//通过证书为该类设置签名
postDefineClass(c, protectionDomain);
return c;
}
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//该getClassLoadingLock获取同步锁,该锁用并发Map保存(享元模式)
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 这里体现了类加载机制中的父优先的查找机制
// 通过上滤直到parent为null
// 这时再去BootstrapClassLoader中查找,在运行用户程序时,这一步一般都是null
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();
//载入字节码到内存
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
//解析连接类
if (resolve) {
resolveClass(c);
}
return c;
}
}