ClassLoader源码分析

层次结构和类图

ClassLoader层次结构:

  ClassLoader源码分析_第1张图片
 
 
UML类图:
 
ClassLoader源码分析_第2张图片
 
  • 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 binary name.  The
     * default implementation of this method searches for classes in the
     * following order:
     *
     * 

     *
     *   
  •  Invoke {@link #findLoadedClass(String)} to check if the class

  •      *   has already been loaded.  

         *
         *   
  •  Invoke the {@link #loadClass(String) loadClass} method

  •      *   on the parent class loader.  If the parent is null the class
         *   loader built-in to the virtual machine is used, instead.  

         *
         *   
  •  Invoke the {@link #findClass(String)} method to find the

  •      *   class.  

         *
         * 
         *
         * 

     

         */
        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 c has
         * already been linked, then this method simply returns. Otherwise, the
         * class is linked as described in the "Execution" chapter of the 
         * href="http://java.sun.com/docs/books/jls/">Java Language Specification.
         * 

         *
         * @param  c
         *         The class to link
         *
         * @throws  NullPointerException
         *          If c is null.
         *
         * @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 Class.
         * Before the Class 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 binary name if this
         * loader has been recorded by the Java virtual machine as an initiating
         * loader of a class with that binary name.  Otherwise
         * null is returned.  

         */
    protected final Class findLoadedClass(String name) 
     

    findSystemClass

     
        /**
         * Finds a class with the specified binary name,
         * loading it if necessary.
         *
         * 

     This method loads the class through the system class loader (see

         * {@link #getSystemClassLoader()}).  The Class object returned
         * might have more than one ClassLoader associated with it.
         * Subclasses of ClassLoader need not usually invoke this method,
         * because most class loaders need to override just {@link  #findClass(String)}.  

          */
    protected final Class findSystemClass(String name)
     

    getParent

        /**
         * Returns the parent class loader for delegation. Some implementations may
         * use null to represent the bootstrap class loader. This method
         * will return null 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 c has
         * already been linked, then this method simply returns. Otherwise, the
         * class is linked as described in the "Execution" chapter of the 
         * href="http://java.sun.com/docs/books/jls/">Java Language  Specification.
         */
    protected final void resolveClass(Class c) 
     
     
     
     
     
     
     
     
     

    你可能感兴趣的:(【Java,SE】)