序言
最近看了看ClassLoader,网上的博客挺多的,大部分都是你抄我的,我抄你的。在他们的基础上,自己打算写一篇,自己对ClassLoader的分析,也就是对现有blog的总结吧。
ClassLoader初始化源码。
在openjdk中可以看到下面的代码。
public Launcher() {
// Create the extension class loader
ClassLoader extcl;
try {
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader");
}
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader");
}
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);
// Finally, install a security manager if requested
String s = System.getProperty("java.security.manager");
if (s != null) {
SecurityManager sm = null;
if ("".equals(s) || "default".equals(s)) {
sm = new java.lang.SecurityManager();
} else {
try {
sm = (SecurityManager)loader.loadClass(s).newInstance();
} catch (IllegalAccessException e) {
} catch (InstantiationException e) {
} catch (ClassNotFoundException e) {
} catch (ClassCastException e) {
}
}
if (sm != null) {
System.setSecurityManager(sm);
} else {
throw new InternalError(
"Could not create SecurityManager: " + s);
}
}
}
可以看到在Launcher构造函数的执行过程如下:
-
通过ExtClassLoader.getExtClassLoader()创建了ExtClassLoader;
-
通过AppClassLoader.getAppClassLoader(ExtClassLoader)创建了AppClassLoader,并将ExtClassLoader设为AppClassLoader的parent
ClassLoader; -
通过Thread.currentThread().setContextClassLoader(loader)把AppClassLoader设为线程的上下文
ClassLoader;
JDK默认ClassLoader:
在jdk中默认了3种的ClassLoader:BootStrapClassLoader、ExtensionClassLoader和AppClassLoader。
- BootStrapClassLoader:它是最顶层的类加载器,是由C++编写而成,
已经内嵌到JVM中了。在JVM启动时会初始化该ClassLoader,它主要用来读取Java的
核心类库JRE/lib/rt.jar中所有的class文件,这个jar文件中包含了java规范定义的所有接口及实现。 - ExtensionClassLoader:它是用来读取Java的一些扩展类库,如读取JRE/lib/ext/*.jar中的包等(这里要注意,有些版本的是没有ext这个目录的)。
- AppClassLoaderBootstrp
loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为
ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是
sun.misc.Launcher$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。
ClassLoader源码阅读
##成员变量
private final ClassLoader parent;
父类的加载器,所有的新的变量都必须在它之后,英文: The parent class loader for delegation.Note: VM hardcoded the offset of this field, thus all new fields must be added after it.
private final ConcurrentHashMap parallelLockMap;
当前ClassLoader在并发情况下,一个锁的的对象。 Maps class name to the corresponding lock object when the current class loader is parallel capable. Note: VM also uses this field to decide if the current class loader is parallel capable and the appropriate lock object for class loading.
private final Map package2cert;
每个包的证书,是个HashTable
private static final Certificate[] nocerts = new Certificate[0];
Shared among all packages with unsigned classes
private final Vector> classes = new Vector<>();
这个class loader加载的所有类,这些类是从开始被GC到gc结束 The classes loaded by this class loader. The only purpose of this table is to keep the classes from being GC’ed until the loader is GC’ed.
private final ProtectionDomain defaultDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, this, null);
貌似是读写的策略,The “default” domain. Set as the default ProtectionDomain on newly created classes.
private final Set domains;
The initiating protection domains for all classes loaded by this loader
构建函数
私有的构造函数
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
domains =
Collections.synchronizedSet(new HashSet<ProtectionDomain>());
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
domains = new HashSet<>();
assertionLock = this;
}
}
也就是分为当前的ClassLoader是否被加载2种情况:ParallelLoaders.isRegistered(this.getClass())来判断是否可以并行
保护性的构造函数
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
checkCreateClassLoader():是校验下创建ClassLoader的权限
parent:是创建ClassLoader的父节点
getSystemClassLoader():是获取系统的ClassLoader,作为当前节点的父节点
3. loadClass
resolve:在虚拟机中找到一个类二进制,再根据resolve参数判断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();
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;
}
}
先进行getClassLoadingLock(以后会详细分析),然后查找已加载的类,在从父类ClassLoader查找,最后查找Bootstrap的ClassLoader
resolveClass:链接指定的类。这个方法给Classloader用来链接一个类,如果这个类已经被链接过了,那么这个方法只做一个简单的返回。否则,这个类将被按照 Java™规范中的Execution描述进行链接
##参照:
http://www.hollischuang.com/archives/199