1、概述
ClassLoader的基本概念以及分类进行了详细的介绍,具体内容可以查看:水煮Java虚拟机 - 类加载器ClassLoader分析
ClassLoader的源码进行简要分析,由于
ClassLoader相关的源码比较多,内容比较长,将分为4篇文章进行介绍,选取的源码基于JDK1.8版本,涉及到的类如下:
java.lang.ClassLoaderjava.security.SecureClassLoaderjava.net.URLClassLoadersun.misc.Launchersun.misc.Launcher$AppClassLoadersun.misc.Launcher$ExtClassLoader

2、ClassLoader
java.lang.ClassLoader
是一抽象类,是所有Java类加载器的父类(不包括启动类加载器,Bootstrap ClassLoader
是由C++语言实现的),整个类的源码相对较多,接下来会按照 核心属性、构造方法和其他方法逐一进行分析。
2.1 核心属性
/*** 委派的父类加载器*/private final ClassLoader parent;/*** 类名对应的锁对象集合,当前类加载器具有并行能力时,将类名映射到相应的锁对象* VM会根据这个字段来判断当前类加载器是否具有并行能力*/private final ConcurrentHashMap<String, Object> parallelLockMap;/*** 包名映射到 Certificate 的哈希集合*/private final Map <String, Certificate[]> package2certs;/*** 无签名类共享的证书数组*/private static final Certificate[] nocerts = new Certificate[0];/*** 记录当前类加载器加载的所有类,用于防止类被GC*/private final Vector<Class<?>> classes = new Vector<>();/*** 默认的权限域*/private final ProtectionDomain defaultDomain =new ProtectionDomain(new CodeSource(null, (Certificate[]) null),null, this, null);/*** 当前类加载器加载的所有类对应的权限域*/private final Set<ProtectionDomain> domains;/*** 当前类加载器定义的包对象集合,每个包会被映射成一个 Package 对象*/private final HashMap<String, Package> packages = new HashMap<>();/*** 系统类加载器*/private static ClassLoader scl;/*** 系统类加载器是否已设置标志*/private static boolean sclSet;/*** 所有加载的本地库名称集合*/private static Vector<String> loadedLibraryNames = new Vector<>();/*** 属于系统类的本地库集合*/private static Vector<NativeLibrary> systemNativeLibraries= new Vector<>();/*** 与类加载器关联的本地库集合*/private Vector<NativeLibrary> nativeLibraries = new Vector<>();/*** 正在被加载或卸载的本地库集合*/private static Stack<NativeLibrary> nativeLibraryContext = new Stack<>();/*** 用户搜索路径*/private static String usr_paths[];/*** 系统搜索路径*/private static String sys_paths[];/*** 断言锁对象*/final Object assertionLock;/*** 默认的断言检查状态*/private boolean defaultAssertionStatus = false;/*** 包名映射到布尔型的断言状态,如果该字段为null,则将断言状态查询委托给VM*/private Map<String, Boolean> packageAssertionStatus = null;/*** 类全限名映射到布尔型的断言状态,如果该字段为null,则将断言状态查询委托给VM*/Map<String, Boolean> classAssertionStatus = null;
2.2 构造方法
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// 无并行能力// 并行锁对象集合为nullparallelLockMap = null;package2certs = new Hashtable<>();domains = new HashSet<>();assertionLock = this;}}protected ClassLoader(ClassLoader parent) {this(checkCreateClassLoader(), parent);}protected ClassLoader() {this(checkCreateClassLoader(), getSystemClassLoader());}
ParallelLoaders
是ClassLoader
内部静态类,其源码如下:private static class ParallelLoaders {private ParallelLoaders() {}// the set of parallel capable loader types// 具有并行能力的加载器类型集合private static final Set<Class<? extends ClassLoader>> loaderTypes =Collections.newSetFromMap(new WeakHashMap<Class<? extends ClassLoader>, Boolean>());static {synchronized (loaderTypes) {// 添加 ClassLoader 类loaderTypes.add(ClassLoader.class);}}/*** Registers the given class loader type as parallel capabale.* Returns {@code true} is successfully registered; {@code false} if* loader's super class is not registered.*/static boolean register(Class<? extends ClassLoader> c) {synchronized (loaderTypes) {// 判断父类是否具有并行能力if (loaderTypes.contains(c.getSuperclass())) {// register the class loader as parallel capable// if and only if all of its super classes are.// Note: given current classloading sequence, if// the immediate super class is parallel capable,// all the super classes higher up must be too.// 当父类具有并行能力时,将 c 添加到 loaderTypes 中loaderTypes.add(c);return true;} else {return false;}}}/*** Returns {@code true} if the given class loader type is* registered as parallel capable.*/static boolean isRegistered(Class<? extends ClassLoader> c) {// 判断类加载器是否已注册为并行类加载器synchronized (loaderTypes) {return loaderTypes.contains(c);}}}checkCreateClassLoader()
方法用于判断调用线程是否具有创建新的类加载器的权限,它会调用java.lang.SecurityManager.checkCreateClassLoader()
方法,如下:private static Void checkCreateClassLoader() {SecurityManager security = System.getSecurityManager();if (security != null) {// 调用 java.lang.SecurityManager.checkCreateClassLoader() 方法security.checkCreateClassLoader();}return null;}getSystemClassLoader()
方法用于获取系统类加载器,如下:@CallerSensitivepublic static ClassLoader getSystemClassLoader() {// 初始化系统类加载器initSystemClassLoader();if (scl == null) {return null;}// 创建 SecurityManager 对象SecurityManager sm = System.getSecurityManager();if (sm != null) {// 判断类加载器权限checkClassLoaderPermission(scl, Reflection.getCallerClass());}return scl;}private static synchronized void initSystemClassLoader() {// 如果系统类加载器未设置if (!sclSet) {if (scl != null)throw new IllegalStateException("recursive invocation");// 创建 Launcher 对象sun.misc.Launcher l = sun.misc.Launcher.getLauncher();if (l != null) {Throwable oops = null;// 从 Launcher 中获取 ClassLoader,并赋值给 sclscl = l.getClassLoader();try {// 赋予系统类加载器 scl 特权scl = AccessController.doPrivileged(new SystemClassLoaderAction(scl));} catch (PrivilegedActionException pae) {oops = pae.getCause();if (oops instanceof InvocationTargetException) {oops = oops.getCause();}}if (oops != null) {if (oops instanceof Error) {throw (Error) oops;} else {// wrap the exceptionthrow new Error(oops);}}}sclSet = true;}}
2.3 loadClass
#loadClass(String name, boolean resolve)方法负责加载指定名称的类,代码如下:
/*** 加载指定名称的类** @param name 类名称* @param resolve 是否需要解析* @return Class 对象* @throws ClassNotFoundException*/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 {// 判断父类加载器是否为nullif (parent != null) {// 父类加载器不为null,则委托给父类加载器加载c = parent.loadClass(name, false);} else {// 父类加载器为null,则委托给启动类加载器进行加载c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}// 若没有找到,则调用 findClass 方法查找此类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();}}// 判断是否类需要解析,若需要解析,则调用 resolveClass 方法if (resolve) {// 调用本地 resolveClass0 方法resolveClass(c);}return c;}}public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}
#getClassLoadingLock(String className)
方法是为了获取加载类对应的锁对象,其实现如下:protected Object getClassLoadingLock(String className) {// 锁对象为 ClassLoader 本身Object lock = this;// 如果 parallelLockMap 不为空if (parallelLockMap != null) {Object newLock = new Object();// 当className没有对应的值时,设置新值 newLocklock = parallelLockMap.putIfAbsent(className, newLock);if (lock == null) {lock = newLock;}}return lock;}
2.4 findLoadedClass
#findLoadedClass(String name)方法,用于从当前
ClassLoader实例对象的缓存中查找已加载的类,调用的是native方法,源码如下:
protected final Class<?> findLoadedClass(String name) {if (!checkName(name))return null;// 调用本地方法return findLoadedClass0(name);}private native final Class<?> findLoadedClass0(String name);
#checkName(String name)
方法用于检查类名是否为空或者是有效的二进制名称,代码如下:private boolean checkName(String name) {if ((name == null) || (name.length() == 0))return true;if ((name.indexOf('/') != -1)|| (!VM.allowArraySyntax() && (name.charAt(0) == '[')))return false;return true;}
2.5 findBootstrapClassOrNull
#findBootstrapClassOrNull(String name)方法,用于根据类名获取被启动类加载器加载的类,调用的是native方法,如下:
private Class<?> findBootstrapClassOrNull(String name){// 检查类名是否符合规范if (!checkName(name)) return null;// 调用本地方法return findBootstrapClass(name);}// return null if not foundprivate native Class<?> findBootstrapClass(String name);
2.6 findClass
#findClass(String name)方法没有任何实现,它应该被类加载器的实现重写,该实现按照委托模型来加载类,如下:
protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}
若是找不到相应类,则直接抛出 ClassNotFoundException
异常;
2.7 findSystemClass
#findSystemClass(String name)方法负责从系统类加载器中查找指定类,若找不到,则从启动类加载器中查找,如下:
protected final Class<?> findSystemClass(String name)throws ClassNotFoundException{// 获取系统类加载器ClassLoader system = getSystemClassLoader();// 若系统类加载器为空if (system == null) {// 判断类名是否符合规范if (!checkName(name))throw new ClassNotFoundException(name);// 从启动类加载器中查找指定类Class<?> cls = findBootstrapClass(name);if (cls == null) {// 未找到,直接抛出 ClassNotFoundException 异常throw new ClassNotFoundException(name);}return cls;}// 从系统类加载器中查找指定类return system.loadClass(name);}
(未完待续)由于篇幅有限,关于 ClassLoader 剩下的方法将在下一篇文章进行分析,具体有:
defineClass
resolveClass
getResource
definePackage
参考资料
【1】ClassLoader 源码分析
【2】Java 安全模型介绍
【3】分布式Java应用基础与实践
【4】《jdk8u源码分析》sun.misc.Launcher
文章转载自然笑,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




