JavaJVM之ClassLoader源码分析

层次结构和类图

ClassLoader层次结构:

 
UML类图:

 
  • sun.misc.Launcher.ExtClassLoader
  • sun.misc.Launcher.AppClassLoader
 

显式加载类

在代码中显式加载某个类,有三种方法:
  1. this.getClass().getClassLoader().loadClass()
  2. Class.forName()
  3. MyClassLoader.findClass()

ClassLoader.loadClass()

ClassLoader.loadClass()的加载步骤为:
  1. 调用 findLoadedClass(String) 来检查是否已经加载类。
  2. 在父类加载器上调用 loadClass 方法。如果父类加载器为null,则使用虚拟机的内置类加载器。
  3. 调用 findClass(String) 方法查找类。

 

    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:
     *
     * <p><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> 
     */
    protected synchronized Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
    {
    // First, check if the class has already been loaded
    Class c = findLoadedClass(name);
    if (c == null) {
        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.
            c = findClass(name);
        }
    }
    if (resolve) {
        resolveClass(c);
    }
    return c;
    }

URLClassLoader.findClass()

ClassLoader.loadClass()的最后一步是调用findClass(),这个方法在ClassLoader中并未实现,由其子类负责实现。

findClass()的功能是找到class文件并把字节码加载到内存中。

自定义的ClassLoader一般覆盖这个方法。——以便使用不同的加载路径

 
    /* The search path for classes and resources */
    URLClassPath ucp;
    /* The context to be used when loading classes and resources */
    private AccessControlContext acc;
/**
     * Finds and loads the class with the specified name from the URL search
     * path. Any URLs referring to JAR files are loaded and opened as needed
     * until the class is found.
     *
     * @param name the name of the class
     * @return the resulting class
     * @exception ClassNotFoundException if the class could not be found
     */
    protected Class<?> findClass(final String name)
     throws ClassNotFoundException
    {
    try {
        return (Class)
        AccessController.doPrivileged(new PrivilegedExceptionAction() {
            public Object run() throws ClassNotFoundException {
            String path = name.replace('.''/').concat(".class");
            // 1. URLClassPath ucp,帮助获取class文件字节流
            //    URLClassPath会用FileLoader或者JarLoader去加载字节码 
            Resource res = ucp.getResource(path, false); 
            if (res != null) {
                try {
                // 2. defineClass,创建类对象,将字节流解析成JVM能够识别的Class对象。
                return defineClass(name, res, true);
                } catch (IOException e) {
                throw new ClassNotFoundException(name, e);
                }
            } else {
                throw new ClassNotFoundException(name);
            }
            }
        }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        throw (ClassNotFoundException) pae.getException();
    }
    }

ClassLoader.resolveClass()

加载完字节码后,会根据需要进行验证、解析。
    /**
     * Links the specified class.  This (misleadingly named) method may be
     * used by a class loader to link a class.  If the class <tt>c</tt> has
     * already been linked, then this method simply returns. Otherwise, the
     * class is linked as described in the "Execution" chapter of the <a
     * href="http://java.sun.com/docs/books/jls/">Java LanguageSpecification</a>.
     * </p>
     *
     * @param  c
     *         The class to link
     *
     * @throws  NullPointerException
     *          If <tt>c</tt> is <tt>null</tt>.
     *
     * @see  #defineClass(String, byte[], int, int)
     */
    protected final void resolveClass(Class<?> c) {
    resolveClass0(c);
    }
    private native void resolveClass0(Class c);

自定义加载器

  • findClass()定义加载路径

findClass()的功能是找到class文件并把字节码加载到内存中。

自定义的ClassLoader一般覆盖这个方法。——以便使用不同的加载路径

在其中调用defineClass()解析字节码。

  • loadClass()定义加载机制

自定义的加载器可以覆盖该方法loadClass(),以便定义不同的加载机制

例如Servlet中的WebappClassLoader覆盖了该方法,在WEB-INFO/classes目录下查找类文件;在加载时,如果成功,则缓存到ResourceEntry对象。——不同的加载机制。

 

AppClassLoader覆盖了loadClass()方法。

如果自定义的加载器仅覆盖了findClass,而未覆盖loadClass(即加载规则一样,但加载路径不同);则调用getClass().getClassLoader()返回的仍然是AppClassLoader!因为真正load类的,还是AppClassLoader。

  • 实现类的热部署

JVM默认不能热部署类,因为加载类时会去调用findLoadedClass(),如果类已被加载,就不会再次加载。

JVM判断类是否被加载有两个条件:完整类名是否一样、ClassLoader是否是同一个。

所以要实现热部署的话,只需要使用ClassLoader的不同实例来加载。


MyClassLoader cl1 = new MyClassLoader();
Class c1 = cl1.findClass("Test.class");
c1.newInstance();

MyClassLoader cl2 = new MyClassLoader();
Class c2 = cl2.findClass("Test.class");
c2.newInstance();

上例中的c1和c2就是两个不同的实例。

如果用同一个ClassLoader实例来加载,则会抛LinkageError。

 

  • 不可覆盖的final方法

defineClass

    /**
     * Converts an array of bytes into an instance of class <tt>Class</tt>.
     * Before the <tt>Class</tt> can be used it must be resolved.
     */
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
 

findLoadedClass

    /**
     * Returns the class with the given <a href="#name">binary name</a> if this
     * loader has been recorded by the Java virtual machine as an initiating
     * loader of a class with that <a href="#name">binary name</a>.  Otherwise
     * <tt>null</tt> is returned.  </p>
     */
protected final Class<?> findLoadedClass(String name) 
 

findSystemClass

 
    /**
     * Finds a class with the specified <a href="#name">binary name</a>,
     * loading it if necessary.
     *
     * <p> This method loads the class through the system class loader (see
     * {@link #getSystemClassLoader()}).  The <tt>Class</tt> object returned
     * might have more than one <tt>ClassLoader</tt> associated with it.
     * Subclasses of <tt>ClassLoader</tt> need not usually invoke this method,
     * because most class loaders need to override just {@link #findClass(String)}.  </p>
     */
protected final Class<?> findSystemClass(String name)
 

getParent

    /**
     * Returns the parent class loader for delegation. Some implementations may
     * use <tt>null</tt> to represent the bootstrap class loader. This method
     * will return <tt>null</tt> in such implementations if this class loader's
     * parent is the bootstrap class loader.
     */
public final ClassLoader getParent()
 

resolveClass

 /**
     * Links the specified class.  This (misleadingly named) method may be
     * used by a class loader to link a class.  If the class <tt>c</tt> has
     * already been linked, then this method simply returns. Otherwise, the
     * class is linked as described in the "Execution" chapter of the <a
     * href="http://java.sun.com/docs/books/jls/">Java Language Specification</a>.
     */
protected final void resolveClass(Class<?> c)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python打包库_Python 打包自己的库到 PYPI (可pip安装)

背景在我们安装 Python 库的时候&#xff0c;通常我们都是pip install xxx真是又酷炫又方便那么&#xff0c;当我们自己写了一些自认为不错的库&#xff0c;想要分享给大家使用(或者是想要装X时)能不能也能做到这样呢&#xff1f;环境需求已经写好能正常使用的库/方法/项目 (可…

ASP.NET Core Web API使用静态swagger.json文件

前言ASP.NET Core Web API默认集成了Swashbuckle&#xff0c;可以在运行时显示Swagger UI&#xff1a;而Swagger UI实际上是解析的动态生成的swagger.json&#xff1a;app.UseSwagger(); app.UseSwaggerUI(c > c.SwaggerEndpoint("/swagger/v1/swagger.json", &qu…

XenApp共享桌面打开文件警告与桌面文件由于Internet文件安全设置无法打开解决办法...

问题现象 1. 在使用了UPM与文件夹重定向后&#xff0c;个人的桌面路径就会变成一个UNC路径&#xff0c;这个时候如果用户登录共享桌面的话可以看到桌面与快速启动栏的文件与快捷方式&#xff0c;但是打开的时候就会遇到以下错误 这种情况是由于我们放的文件是一个网络路径所导致…

Zookeeper-Zookeeper的配置

前面两篇文章介绍了Zookeeper是什么和可以干什么&#xff0c;那么接下来我们就实际的接触一下Zookeeper这个东西&#xff0c;看看具体如何使用&#xff0c;有个大体的感受&#xff0c;后面再描述某些地方的时候也能在大脑中有具体的印象。本文只关注分布式模式的zookeeper&…

Android插件化开发之动态加载基础之ClassLoader工作机制

类加载器ClassLoader 早期使用过Eclipse等Java编写的软件的同学可能比较熟悉&#xff0c;Eclipse可以加载许多第三方的插件&#xff08;或者叫扩展&#xff09;&#xff0c;这就是动态加载。这些插件大多是一些Jar包&#xff0c;而使用插件其实就是动态加载Jar包里的Class进行…

python运行时间过长怎么优化_Python性能优化的20条建议

1.优化算法时间复杂度算法的时间复杂度对程序的执行效率影响最大&#xff0c;在Python中可以通过选择合适的数据结构来优化时间复杂度&#xff0c;如list和set查找某一个元素的时间复杂度分别是O(n)和O(1)。不同的场景有不同的优化方式&#xff0c;总得来说&#xff0c;一般有分…

周选特辑|一些超棒的开源项目!

编程导航 每周新增资源优选特辑 02编程导航 致力于推荐优质编程资源 &#x1f48e;项目开源仓库&#xff1a;https://github.com/liyupi/code-nav跪求一个 star ⭐️哈喽大家好&#xff01;我是编程导航的小编火宝。美好的一周又过去了&#xff0c;大家有没有认真学习呢&#x…

js字符串函数大全

JS自带函数concat将两个或多个字符的文本组合起来&#xff0c;返回一个新的字符串。var a "hello";var b ",world";var c a.concat(b);alert(c);//c "hello,world"indexOf返回字符串中一个子串第一处出现的索引&#xff08;从左到右搜索&…

Android插件化开发之DexClassLoader动态加载dex、jar小Demo

一、温故动态加载ClassLoader机制 如果对Android的ClassLoader加载机制不熟悉&#xff0c;猛戳Android插件化开发动态加载基础之ClassLoader工作机制 http://blog.csdn.net/u011068702/article/details/53248960 二、介绍 我们知道在Android中可以跟java一样实现动态加载jar&…

js监听多个事件_JavaScript中的事件与异常捕获解析

这篇文章主要给大家介绍了关于JavaScript中事件与异常捕获的相关资料&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;写的十分的全面细致&#xff0c;具有一定的参考价值&#xff0c;对此有需要的朋友可以参考学习下。如有不足之处&#xff0c;欢迎批评指正。事件处理…

GDUFE ACM-1045

题目&#xff1a;http://acm.gdufe.edu.cn/Problem/read/id/1045 Elevator Time Limit: 2000/1000ms (Java/Others) Problem Description: The highest building in our city has only one elevator. A request list is made up with N positive numbers. The numbers denote a…

mongodb的IO测试工具 mongoperf

之前没发现mongoperf这个工具&#xff0c;测试IO的状态用的是iostat来进行观察。 mongoperf < myjsonconfigfile echo "{nThreads:2,fileSizeMB:20,w:true,r:true}" | mongoperf参数示列如下&#xff1a; {nThreads:<n>, fileSizeMB:<n>, sleepMicros…

C#多线程开发-使用并发集合

前言大家好&#xff0c;我是阿辉。在C#语言中当需要处理并发的场景时&#xff0c;就需要程序员使用最合理的数据结构。那么哪些数据结构是支持和可以在并行计算中被使用的呢。首先这些数据结构具备可伸缩性&#xff0c;尽可能地避免锁(会造成多个线程的等待&#xff0c;防止资源…

Android之用sharedUserId来实现不同应用(APK)数据共享

android:sharedUserId 当APK安装的时候&#xff0c;userid这个标志就会产生。APK在设备上的整个生命周期中&#xff0c;这个ID不再改变。不同设备上同一个应用包可能有不同的userid&#xff0c;重要的是在给定的设备上&#xff0c;每个应用包有自己独立的userid。 userid的特点…

windows 下安装wamp环境

一直以来都是学习在Linux下安装lanmp环境&#xff0c;在Windows下都是用的集成工具比如appserv现在来安装Windows版本的lamp都是从官网下载的资源在Windows下以后还会编辑更多的东西。我的文章都会以后都有更新&#xff0c;因为有时候有点想法&#xff0c;如果不实践的话会忘记…

python编程发展_编程的发展史及Python简介

一.编程语言演变史编程语言分为三类&#xff0c;分别是机器语言&#xff0c;汇编语言和高级程序语言。1.机器语言&#xff1a;用0和1表示二进制跟计算机进行直接的沟通交流&#xff0c;对硬件进行直接操作。2.汇编语言&#xff1a;用简单的英文标签来表示二进制数&#xff0c;对…

iOS ShareSDK 使用

流量精灵软件中&#xff0c;也在大部分地方使用到了shareSDK 这个三方开源库。具体的有两种需求 a、弹出所有分享模块 b、只弹出指定的平台&#xff1a;如微信朋友圈和QQ 。 配置方法&#xff0c;三方库中也很详细&#xff0c;这里我只有写出自出自己代码实现的部分 这里只写自…