介绍
ClassLoader 顾名思义就是类加载器 ClassLoader 是一个抽象类 没有父类
作用
1.负责将 Class 加载到 JVM 中
2.审查每个类由谁加载(父优先的等级加载机制)
3.将 Class 字节码重新解析成 JVM 统一要求的对象格式
常量&变量
//注册本地方法
private static native void registerNatives();
static {
registerNatives();
}
// The parent class loader for delegation
// Note: VM hardcoded the offset of this field, thus all new fields
// must be added *after* it.
//父类加载器,需要与BuiltinClassLoader中的parent区分
private final ClassLoader parent;
// 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 ConcurrentHashMap<String, Object> parallelLockMap;
// Hashtable that maps packages to certs
// 将包名映射到身份证书
private final Map <String, Certificate[]> package2certs;
// Shared among all packages with unsigned classes
private static final Certificate[] nocerts = new Certificate[0];
// 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 Vector<Class<?>> classes = new Vector<>();
// The "default" domain. Set as the default ProtectionDomain on newly
// created classes.
private final ProtectionDomain defaultDomain =
new ProtectionDomain(new CodeSource(null, (Certificate[]) null),
null, this, null);
// The packages defined in this class loader. Each package name is mapped
// to its corresponding Package object.
// @GuardedBy("itself")
// 记录当前类加载器定义的包
private final HashMap<String, Package> packages = new HashMap<>();
// The class loader for the system
// @GuardedBy("ClassLoader.class")
//system class loader,可能是内置的AppClassLoader(默认),也可能是自定义的类加载器
private static ClassLoader scl;
// Set to true once the system class loader has been set
// @GuardedBy("ClassLoader.class")
private static boolean sclSet;
// All native library names we've loaded.
private static Vector<String> loadedLibraryNames = new Vector<>();
// Native libraries belonging to system classes.
private static Vector<NativeLibrary> systemNativeLibraries
= new Vector<>();
// Native libraries associated with the class loader.
private Vector<NativeLibrary> nativeLibraries = new Vector<>();
// native libraries being loaded/unloaded.
private static Stack<NativeLibrary> nativeLibraryContext = new Stack<>();
// The paths searched for libraries
private static String usr_paths[];
private static String sys_paths[];
final Object assertionLock;
// The default toggle for assertion checking.
// @GuardedBy("assertionLock")
private boolean defaultAssertionStatus = false;
// Maps String packageName to Boolean package default assertion status Note
// that the default package is placed under a null map key. If this field
// is null then we are delegating assertion status queries to the VM, i.e.,
// none of this ClassLoader's assertion status modification methods have
// been invoked.
// @GuardedBy("assertionLock")
private Map<String, Boolean> packageAssertionStatus = null;
// Maps String fullyQualifiedClassName to Boolean assertionStatus If this
// field is null then we are delegating assertion status queries to the VM,
// i.e., none of this ClassLoader's assertion status modification methods
// have been invoked.
// @GuardedBy("assertionLock")
Map<String, Boolean> classAssertionStatus = null;
构造方法
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
//类加载器是否可并行
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
assertionLock = this;
}
}
/**
* Creates a new class loader using the specified parent class loader for
* delegation.
*
* <p> If there is a security manager, its {@link
* SecurityManager#checkCreateClassLoader()
* <tt>checkCreateClassLoader</tt>} method is invoked. This may result in
* a security exception. </p>
*
* @param parent
* The parent class loader
*
* @throws SecurityException
* If a security manager exists and its
* <tt>checkCreateClassLoader</tt> method doesn't allow creation
* of a new class loader.
*
* @since 1.2
*/
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
/**
* Creates a new class loader using the <tt>ClassLoader</tt> returned by
* the method {@link #getSystemClassLoader()
* <tt>getSystemClassLoader()</tt>} as the parent class loader.
*
* <p> If there is a security manager, its {@link
* SecurityManager#checkCreateClassLoader()
* <tt>checkCreateClassLoader</tt>} method is invoked. This may result in
* a security exception. </p>
*
* @throws SecurityException
* If a security manager exists and its
* <tt>checkCreateClassLoader</tt> method doesn't allow creation
* of a new class loader.
*/
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
常用方法
loadClass
/**
* Loads the class with the specified <a href="#name">binary name</a>.
* This method searches for classes in the same manner as the {@link
* #loadClass(String, boolean)} method. It is invoked by the Java virtual
* machine to resolve class references. Invoking this method is equivalent
* to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
* false)</tt>}.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class was not found
* 加载指定二进制名称的类
*/
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
/**
* Loads the class with the specified <a href="#name">binary name</a>. The
* default implementation of this method searches for classes in the
* following order:
*
* <ol>
*
* <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
* has already been loaded. </p></li>
*
* <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
* on the parent class loader. If the parent is <tt>null</tt> the class
* loader built-in to the virtual machine is used, instead. </p></li>
*
* <li><p> Invoke the {@link #findClass(String)} method to find the
* class. </p></li>
*
* </ol>
*
* <p> If the class was found using the above steps, and the
* <tt>resolve</tt> flag is true, this method will then invoke the {@link
* #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
*
* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
* #findClass(String)}, rather than this method. </p>
*
* <p> Unless overridden, this method synchronizes on the result of
* {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
* during the entire class loading process.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @param resolve
* If <tt>true</tt> then resolve the class
* 如果为true则解析该类
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class could not be found
*/
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
//校验class是否被加载
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();
//父类加载器没有找到,再调用本身(这个本身包括ext和app)的findClass(name)来查找父类
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;
}
}
getResource
/**
* Finds the resource with the given name. A resource is some data
* (images, audio, text, etc) that can be accessed by class code in a way
* that is independent of the location of the code.
*
* <p> The name of a resource is a '<tt>/</tt>'-separated path name that
* identifies the resource.
*
* <p> This method will first search the parent class loader for the
* resource; if the parent is <tt>null</tt> the path of the class loader
* built-in to the virtual machine is searched. That failing, this method
* will invoke {@link #findResource(String)} to find the resource. </p>
*
* @apiNote When overriding this method it is recommended that an
* implementation ensures that any delegation is consistent with the {@link
* #getResources(java.lang.String) getResources(String)} method.
*
* @param name
* The resource name
*
* @return A <tt>URL</tt> object for reading the resource, or
* <tt>null</tt> if the resource could not be found or the invoker
* doesn't have adequate privileges to get the resource.
*
* @since 1.1
* 获得指定名称的资源 图像,音频,文本等
*/
public URL getResource(String name) {
URL url;
if (parent != null) {
//搜索父类加载器的资源
url = parent.getResource(name);
} else {
//不存在父类,搜索虚拟机默认的类加载器的路径,
url = getBootstrapResource(name);
}
//仍然获取不到资源
if (url == null) {
//调用findResource(String)来查找资源
url = findResource(name);
}
return url;
}
双亲委派模型
提起Classs Loader 的类加载机制就不得不说说它的“双亲委派模型“
ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是组合关系),虚拟机内置的启动类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。
可以发现委托是从下向上,然后具体查找过程却是自上至下。
-
最高一层是BootStrap Class Loader
它是在JVM 启动时候创建的,负载装载核心的Java 类, 比如Object , System String 等,主要位于jre/lib/rt.jar 中。
-
第二层是Platform ClassLoader
即平台类加载器,负责装载扩展系统类,比如XMl, 加密,压缩相关的功能类,主要位于jre/lib/ext/*.jar
-
第三层类是Application ClassLoader
即应用类加载器,主要加载用户自定义的ClassPath 路径下的类,主要位于ClassPath 中的jar.