JVM学习(8)不同类的加载器作用与加载动作分析

本文深入分析JVM中不同类加载器的作用和加载动作,探讨类加载器的层级关系,通过实例展示了如何查看类加载器关系、获取字节码位置,并介绍了获取ClassLoader的多种途径。
摘要由CSDN通过智能技术生成

不同类的加载器作用与加载动作分析

首先我们来看一下类加载器的关系图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RAUHwde4-1581763577387)(E:\Typora\图片\2020-02-15.01.png)]

这个很明显说的就是一个类加载器的一个层次关系那么怎么用代码查看类加载器的一个关系呢?

了解类加载器的流程

实列1

public class MyTest8 {
    public static void main(String[] args) {
        ClassLoader classLoader= ClassLoader.getSystemClassLoader();//ClassLoader.getSystemClassLoader():获取类加载器
        System.err.println(classLoader);
        while (classLoader!=null){
            classLoader= classLoader.getParent();//classLoader.getParent():获取该加载器的父加载器
            System.err.println(classLoader);
        }
    }
}

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JO3vjMQE-1581763577388)(E:\Typora\图片\2020-02-15.02.png)]

如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rIJ5AGMa-1581763577388)(E:\Typora\图片\2020-02-10-02.png)]

​ 这里的结果我们可以看到先获取的到的AppClassLoader接着就是ExtClassLoader最后就是null,那么为什么最后一个根类加载器为null呢这里我们需要看源码里面的注释,大家可以看看这句翻译(null in such implementations if this class was loaded by the bootstrap 如果此类是由引导程序加载的,则在此类实现中为空

​ 这里就很明显的表现出来类加载器的一个层次关系,接下来我们看看ClassLoader.getSystemClassLoader():的源码,跟以前一样还是注释一句一句分析。

  /**
     * Returns the system class loader for delegation.  This is the default 返回用于委派的系统类加载器。这是默认值
     * delegation parent for new <tt>ClassLoader</tt> instances, and is 为新的类装入器实例委派父实例,并且
     * typically the class loader used to start the application. 通常是用来启动应用程序的类加载器。
     *
     * <p> This method is first invoked early in the runtime's startup 此方法首先在运行时启动的早期调用
     * sequence, at which point it creates the system class loader and sets it
     * as the context class loader of the invoking <tt>Thread</tt>. 序列,此时创建系统类装入器,并将其设置为调用线程的上下文类装入器。
     *
     * <p> The default system class loader is an implementation-dependent
     * instance of this class. 默认的系统类加载器是该类的依赖于实现的实例。
     *
     * <p> If the system property "<tt>java.system.class.loader</tt>" is defined
     * when this method is first invoked then the value of that property is
     * taken to be the name of a class that will be returned as the system
     * class loader.  The class is loaded using the default system class loader
     * and must define a public constructor that takes a single parameter of
     * type <tt>ClassLoader</tt> which is used as the delegation parent.  An
     * instance is then created using this constructor with the default system
     * class loader as the parameter.  The resulting class loader is defined
     * to be the system class loader.如果在首次调用此方法时定义了系统属性“<tt>java.system.class.loader</tt>”,则该属性的值将被视为将作为系统类装入器返回的类的名称。类使用默认的系统类加载器加载,并且必须定义一个公共构造函数,该构造函数接受一个类型为<tt>class loader</tt>的参数,该参数用作委托父级。然后使用此构造函数创建一个实例,并使用默认的系统类加载器作为参数。生成的类加载器被定义为系统类加载器。
     *
     * <p> If a security manager is present, and the invoker's class loader is
     * not <tt>null</tt> and the invoker's class loader is not the same as or
     * an ancestor of the system class loader, then this method invokes the
     * security manager's {@link
     * SecurityManager#checkPermission(java.security.Permission)
     * <tt>checkPermission</tt>} method with a {@link
     * RuntimePermission#RuntimePermission(String)
     * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
     * access to the system class loader.  If not, a
     * <tt>SecurityException</tt> will be thrown.  </p> 如果存在安全管理器,并且调用程序的类加载器不是<tt>null</tt>,并且调用程序的类加载器与系统类加载器不相同或不是系统类加载器的祖先,然后,此方法使用{@link RuntimePermission(String)<tt>RuntimePermission(“getClassLoader”)</tt>}权限调用安全管理器的{@link security manager\checkPermission(java.security.Permission)<tt>checkPermission</tt>}方法来验证对系统类装入器的访问。否则,将抛出一个<tt>安全异常</tt>。
     *
     * @return  The system <tt>ClassLoader</tt> for delegation, or
     *          <tt>null</tt> if none 系统<tt>类加载器</tt>用于委派,或者<tt>空</tt>如果没有
     *
     * @throws  SecurityException 安全接收
     *          If a security manager exists and its <tt>checkPermission</tt>
     *          method doesn't allow access to the system class loader. 如果存在安全管理器,并且它的<tt>checkPermission</tt>方法不允许访问系统类加载器。
     *
     * @throws  IllegalStateException 非法状态异常
     *          If invoked recursively during the construction of the class
     *          loader specified by the "<tt>java.system.class.loader</tt>"
     *          property. 如果在构造由“<tt>java.system.class.loader</tt>”属性指定的类加载器期间递归调用。
     *
     * @throws  Error 错误
     *          If the system property "<tt>java.system.class.loader</tt>"
     *          is defined but the named class could not be loaded, the
     *          provider class does not define the required constructor, or an
     *          exception is thrown by that constructor when it is invoked. The
     *          underlying cause of the error can be retrieved via the
     *          {@link Throwable#getCause()} method. 如果系统属性“<tt>java.system.class.loader</tt>”已定义,但无法加载命名类,则提供程序类未定义所需的构造函数,或者调用该构造函数时该构造函数引发异常。可以通过{@link Throwable#getCause()}方法检索错误的根本原因。
     *
     * @revised  1.4
     */
    @CallerSensitive
    public static ClassLoader getSystemClassLoader() {
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }

大家可以看看翻译试着看源代码的意思,也可以查查相关的文件进行一个深度的解析

通过类加载器获取字节码在什么位置

类加载器是有很多功能的以后我一一写,接下来请看我的代码。

实列2

public class MyTest8 {
    public static void main(String[] args) throws IOException {
       
       ClassLoader classLoader=Thread.currentThread().getContextClassLoader();//获取线程上下文的ClassLoader
        String resourceMyTest8 = "com/jvm/classloader/MyTest8.class"; //定义字节码文件的路径
        Enumeration<URL> enumeration = classLoader.getResources(resourceMyTest8);

        while (enumeration.hasMoreElements()){
            URL url = enumeration.nextElement();//获取地址
            System.err.println(url);
        }


    }
}

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p7kBj3A1-1581763577389)(E:\Typora\图片\2020-02-15.03.png)]

接下来我们来看看classLoader.getResources();

   /**
     * Finds all the resources 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> The search order is described in the documentation for {@link
     * #getResource(String)}.  </p> 搜索顺序在{@link#getResource(String)}的文档中描述。
     *
     * @apiNote When overriding this method it is recommended that an
     * implementation ensures that any delegation is consistent with the {@link
     * #getResource(java.lang.String) getResource(String)} method. This should
     * ensure that the first element returned by the Enumeration's
     * {@code nextElement} method is the same resource that the
     * {@code getResource(String)} method would return. @apiNote重写此方法时,建议实现确保任何委派与{@link#getResource(java.lang.String)getResource(String)}方法一致。这应该确保枚举的{@code nextElement}方法返回的第一个元素与
     *
     * @param  name 名称
     *         The resource name 资源名称
     *
     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
     *          the resource.  If no resources could  be found, the enumeration
     *          will be empty.  Resources that the class loader doesn't have
     *          access to will not be in the enumeration. 资源的{@link java.net.URL<tt>URL</tt>}对象的枚举。如果找不到资源,则枚举将为空。类加载器无权访问的资源将不在枚举中。
     *
     * @throws  IOException 抛出IOException异常
     *          If I/O errors occur 如果发生I/O错误
     *
     * @see  #findResources(String) 
     *
     * @since  1.2
     */
    public Enumeration<URL> getResources(String name) throws IOException {
        @SuppressWarnings("unchecked")
        Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
        if (parent != null) {
            tmp[0] = parent.getResources(name);
        } else {
            tmp[0] = getBootstrapResources(name);
        }
        tmp[1] = findResources(name);

        return new CompoundEnumeration<>(tmp);
    }

​ 大家对着注释进行分析,首先第一段注释就说明了这段代码是干嘛用的(Finds all the resources with the given name. A resource is some data(images, audio, text, etc) that can be accessed by class code in a waythat is independent of the location of the code. 意思是:查找具有给定名称的所有资源。资源是一些数据(图像、音频、文本等),可以通过类代码以独立于代码位置的方式访问。

获得ClassLoader的途径

获取当前类的ClassLoader: clazz.getClassLoader();

获得当前线程上下文的ClassLoader: Thread.currentThread().getContextClassLoader();

获取系统的ClassLoader: ClassLoader.getSystemClassLoader();

Loader的途径

获取当前类的ClassLoader: clazz.getClassLoader();

获得当前线程上下文的ClassLoader: Thread.currentThread().getContextClassLoader();

获取系统的ClassLoader: ClassLoader.getSystemClassLoader();

获得调用者的ClassLoader: DriverManager.getCallerClassLoader();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值