ClassLoader源码

news/2024/12/21 15:49:28 标签: java

介绍

ClassLoader 顾名思义就是类加载器 ClassLoader 是一个抽象类 没有父类

作用

1.负责将 Class 加载到 JVM 中

2.审查每个类由谁加载(父优先的等级加载机制)

3.将 Class 字节码重新解析成 JVM 统一要求的对象格式

常量&变量

java"> 	//注册本地方法
	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;

构造方法

java"> 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

image-20230604054300171

java">    /**
     * 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

java">    /**
     * 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实例对象。

image-20230604054245374

可以发现委托是从下向上,然后具体查找过程却是自上至下

  • 最高一层是BootStrap Class Loader

    它是在JVM 启动时候创建的,负载装载核心的Java 类, 比如Object , System String 等,主要位于jre/lib/rt.jar 中。

  • 第二层是Platform ClassLoader

    即平台类加载器,负责装载扩展系统类,比如XMl, 加密,压缩相关的功能类,主要位于jre/lib/ext/*.jar

  • 第三层类是Application ClassLoader

    即应用类加载器,主要加载用户自定义的ClassPath 路径下的类,主要位于ClassPath 中的jar.


http://www.niftyadmin.cn/n/393609.html

相关文章

chatgpt赋能python:Python可以用C语言吗?——一份详细解读

Python可以用C语言吗&#xff1f;——一份详细解读 Python和C语言是两种常见而重要的编程语言。Python被广泛应用于各种领域&#xff0c;从人工智能到数据科学&#xff0c;而C语言则是系统编程&#xff0c;操作系统和编译器方面最受欢迎的语言之一。许多人认为Python和C语言没…

idea部署Tomcat

创建Web项目 我们首先使用IDEA创建一个普通的java项目 创建好后的项目结构如上图&#xff0c;我创建的项目名称为tomcat&#xff0c;这个项目现在还是一个普通的java项目&#xff0c;想要开发web程序&#xff0c;我们还要做一下操作&#xff0c;首先我们先给项目添加依赖 首先…

Vmware虚拟机实例配置静态IP

最近在给虚拟机配置静态IP的时候&#xff0c;出了一些小问题&#xff0c;本文主要描述操作过程中一些小问题的解决。 主要参考资料: How to set up Linux in VMWare Workstation with static IP (IPv4) 个人配置信息: VMware Workstation Debian 记录一下虚拟机的网卡信息 …

Java 实现在顺序表指定位置插入一个元素

一、思路 1.定义一个pos变量来记录要插入的位置. 2.定义一个usedSize变量来记录元素个数. 3.定义一个data变量来记录要插入的元素值. 4.要保证pos位置合法&#xff0c;也就是不是负数&#xff0c;因为是要保证pos位置前是要有元素&#xff0c;因此也不能大于元素个数. 5.也需要…

打电话用什么耳机好,推荐几款性能表现高的骨传导耳机

近几年有一种新型传播方式的耳机&#xff0c;将声音转化为振动&#xff0c;从而让我们的听觉神经感知到。这种声音传播方式叫做"骨传导"&#xff0c;所以叫做骨传导耳机。因为它不需要通过耳膜进行传播声音&#xff0c;所以可以让耳朵在不接触外界的情况下听到声音。…

chatgpt赋能python:Python可以搜集网上资料吗?

Python 可以搜集网上资料吗&#xff1f; Python 是一种非常流行的编程语言&#xff0c;它广泛应用于数据科学、机器学习、人工智能等领域。作为一名 Python 工程师&#xff0c;我们经常需要在互联网上搜集资料来解决开发中的问题&#xff0c;但是有些人会问&#xff1a;Python…

Python3内置关键字大全

目录 1. 布尔类 True 真 False 假 None 空 2. 逻辑类 and 与 or 或 not 非 3. 判断类 if 条件判断 elif 条件判断 else 条件判断 4. 循环类 for 迭代循环 while 判断循环 break 跳出整个循环 continue 跳出当前循环 5. 定义类 class 类与对象 def 自定义函…

基于 Linux 高性能内存池的 Mempoola 数据缓存队列设计

文章目录 本章内容概述一、项目背景二、项目架构1. 内存池分析2. 内存池设计 三、项目实现1. 链栈 StackAlloc2. 内存池 Mempoola成员变量和功能实现分配器构造函数分配器析构函数分配器分配内存函数分配器回收内存函数分配器构造内存函数分配器析构内存函数 本章总结 本章内容…