美文网首页
Android中的ClassLoader

Android中的ClassLoader

作者: HarryXR | 来源:发表于2017-04-07 10:45 被阅读144次

    ClassLoader分类

    在JVM中,有三个ClassLoader,分别是:

    BootsTrap ClassLoader,Extension ClassLoader,App ClassLoader.
    

    同样的,在Android DVM(ART类似,具体实现不同)中也有三个ClassLoader:

    BootClassLoader:主要用于加载系统类,包括Java和Android的类库
    PathClassLoader:主要加载应用(DVM已安装)中的类,它的加载路径固定,无法指定
    DexClassLoader :可以加载任意路径的Zip,Jar,Apk,可以实现动态加载(热更新,插件化)
    

    PathClassLoader和DexClassLoader的源码

    public class PathClassLoader extends BaseDexClassLoader {
        /**
         * Creates a {@code PathClassLoader} that operates on a given list of files
         * and directories. This method is equivalent to calling
         * {@link #PathClassLoader(String, String, ClassLoader)} with a
         * {@code null} value for the second argument (see description there).
         *
         * @param dexPath the list of jar/apk files containing classes and
         * resources, delimited by {@code File.pathSeparator}, which
         * defaults to {@code ":"} on Android
         * @param parent the parent class loader
         */
        public PathClassLoader(String dexPath, ClassLoader parent) {
            super(dexPath, null, null, parent);
        }
    
        /**
         * Creates a {@code PathClassLoader} that operates on two given
         * lists of files and directories. The entries of the first list
         * should be one of the following:
         *
         * <ul>
         * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
         * well as arbitrary resources.
         * <li>Raw ".dex" files (not inside a zip file).
         * </ul>
         *
         * The entries of the second list should be directories containing
         * native library files.
         *
         * @param dexPath the list of jar/apk files containing classes and
         * resources, delimited by {@code File.pathSeparator}, which
         * defaults to {@code ":"} on Android
         * @param librarySearchPath the list of directories containing native
         * libraries, delimited by {@code File.pathSeparator}; may be
         * {@code null}
         * @param parent the parent class loader
         */
        public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
            super(dexPath, null, librarySearchPath, parent);
        }
    }
    
    public class DexClassLoader extends BaseDexClassLoader {
        /**
         * Creates a {@code DexClassLoader} that finds interpreted and native
         * code.  Interpreted classes are found in a set of DEX files contained
         * in Jar or APK files.
         *
         * <p>The path lists are separated using the character specified by the
         * {@code path.separator} system property, which defaults to {@code :}.
         *
         * @param dexPath the list of jar/apk files containing classes and
         *     resources, delimited by {@code File.pathSeparator}, which
         *     defaults to {@code ":"} on Android
         * @param optimizedDirectory directory where optimized dex files
         *     should be written; must not be {@code null}
         * @param librarySearchPath the list of directories containing native
         *     libraries, delimited by {@code File.pathSeparator}; may be
         *     {@code null}
         * @param parent the parent class loader
         */
        public DexClassLoader(String dexPath, String optimizedDirectory,
                String librarySearchPath, ClassLoader parent) {
            super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
        }
    }
    

    可以看到,两者只有构造方法,均无具体实现方法。
    ClassLoader加载过程
    ================
    PathClassLoader和DexClassLoader 都继承BaseDexClassLoader,先看BaseDexClassLoader的构造方法:

     /**
         * Constructs an instance.
         *
         * @param dexPath the list of jar/apk files containing classes and
         * resources, delimited by {@code File.pathSeparator}, which
         * defaults to {@code ":"} on Android
         * @param optimizedDirectory directory where optimized dex files
         * should be written; may be {@code null}
         * @param librarySearchPath the list of directories containing native
         * libraries, delimited by {@code File.pathSeparator}; may be
         * {@code null}
         * @param parent the parent class loader
         */
        public BaseDexClassLoader(String dexPath, File optimizedDirectory/*odex目录*/,
                String libraryPath, ClassLoader parent) {
            super(parent);
            this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
        }
    

    findClass()方法:

    #BaseDexClassLoader.java
    protected Class<?> findClass(String name) throws ClassNotFoundException {
            List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
           //调用DexPathList.findClass,找到直接返回,找不到直接throw exception
            Class c = pathList.findClass(name, suppressedExceptions);
            if (c == null) {
                ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
                for (Throwable t : suppressedExceptions) {
                    cnfe.addSuppressed(t);
                }
                throw cnfe;
            }
            return c;
        }
    

    这里的pathList是DexPathList实例:

    #DexPathList.java
      public Class findClass(String name, List<Throwable> suppressed) {
            for (Element element : dexElements) {
                DexFile dex = element.dexFile;
                //找到dex file
                if (dex != null) {
                    Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
                    if (clazz != null) {
                        return clazz;
                    }
                }
            }
            if (dexElementsSuppressedExceptions != null) {
                suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
            }
            return null;
        }
    

    DexFile.loadClassBinaryName():

     #DexFile.java
      public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
            return defineClass(name, loader, mCookie, suppressed);
        }
    
        private static Class defineClass(String name, ClassLoader loader, long cookie,
                                         List<Throwable> suppressed) {
            Class result = null;
            try {
                result = defineClassNative(name, loader, cookie);
            } catch (NoClassDefFoundError e) {
                if (suppressed != null) {
                    suppressed.add(e);
                }
            } catch (ClassNotFoundException e) {
                if (suppressed != null) {
                    suppressed.add(e);
                }
            }
            return result;
        }
       //调用本地方法defineClassNative
       private static native Class defineClassNative(String name, ClassLoader loader, 
              Object cookie, DexFile dexFile)throws ClassNotFoundException, NoClassDefFoundError;
    

    DexFile.defineClassNative()具体实现请看这里:
    art\runtime\native\dalvik_system_DexFile.cc
    可以看出,BaseDexClassLoader中有个pathList对象,pathList中包含一个DexFile的数组dexElements,由上面分析知道,dexPath传入的原始dex(.apk,.zip,.jar等)文件在optimizedDirectory文件夹中生成相应的优化后的odex文件,dexElements数组就是这些odex文件的集合,如果不分包一般这个数组只有一个Element元素,也就只有一个DexFile文件,而对于类加载呢,就是遍历这个集合,通过DexFile去寻找。最终调用native方法的defineClass。

    参考

    Android动态加载之ClassLoader详解
    Android中的ClassLoader

    相关文章

      网友评论

          本文标题:Android中的ClassLoader

          本文链接:https://www.haomeiwen.com/subject/hozcattx.html