插件化基础之Java世界

来源:互联网 发布:查询linux ipv6 arp 编辑:程序博客网 时间:2024/05/16 17:44

一: 从ClassLoader.java中的loadClass方法说开去

1:什么是ClassLoader,如何改造一个ClassLoader

public abstract class ClassLoader {}

class loader是一个负责加载classes的对象,将class文件加载到jvm虚拟机中去,程序就可以正确运行了,ClassLoader类是一个抽象类,需要给出类的二进制名称,class loader尝试定位或者产生一个class的数据,一个典型的策略是把二进制名字转换成文件名然后到文件系统中找到该文件。

Android系统中ClassLoader经过优化,其源码已经和Java ClassLoader.java不一致,不过大致思想还是相同的

loadClass有两种重载方式,分别为

    public Class<?> loadClass(String name) throws ClassNotFoundException {        return loadClass(name, false);    }
 protected Class<?> loadClass(String name, boolean resolve)        throws ClassNotFoundException

这两个方法都是完成返回指定类的功能;
在第一个方法中,会调用方法二,并且将resolve设置为false;
根据resolve的值将决定是否调用resolveClass方法;

在Android开发过程中,一般使用方法一即可构造classload实例;不需要特意调用方法二,并指定resolve为true;

resolve的值决定是否调用ClassLoader.java中的resolveClass方法;
该方法的主要作用是

链接指定的类。这个方法给Classloader用来链接一个类,如果这个类已经被链接过了,那么这个方法只做一个简单的返回。否则,这个类将被按照 Java™规范中的Execution描述进行链接

二:详解loadClass(String name, boolean resolve)

    /**     * 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>     *     *     * @param  name     *         The <a href="#name">binary name</a> of the class     *     * @param  resolve     *         If <tt>true</tt> then resolve the class     *     * @return  The resulting <tt>Class</tt> object     *     * @throws  ClassNotFoundException     *          If the class could not be found     */    // Android-removed: Remove references to getClassLoadingLock    //                   Remove perf counters.    //    // <p> Unless overridden, this method synchronizes on the result of    // {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method    // during the entire class loading process.    protected 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);                }            }            return c;    }

在个方法的注释中,我们有几个重要关注的地方:
1:
同步getClassLoadingLock方法,当时方法体力确没有,这是因为Android-removed: Remove references to getClassLoadingLock 和 move perf counters.

2:
*

If the class was found using the above steps, and the
* resolve flag is true, this method will then invoke the {@link
* #resolveClass(Class)} method on the resulting Class object.
这段注释的意思是:如果找到class之后,如果resolve为true,则会调用resolveClass链接这个class

3: loadClass(String name, boolean resolve)的主要作用为

使用指定的二进制名称来加载类,

首先检查该类是否被加载,如果被加载则返回,如下

classloader.java

Class<?> c = findLoadedClass(name);

如果没有相关类返回,
如果父类类加载器不为空,则调用ClassLoader.java

loadClass(String)方法

返回该类

如果父加载器为null,类加载器装载虚拟机内置的加载器调用findBootstrapClassOrNull(String)方法装载类,

    /**     * Returns a class loaded by the bootstrap class loader;     * or return null if not found.     */    private Class<?> findBootstrapClassOrNull(String name)    {        return null;    }

该过程即常说的双亲委托模型,loadClass除非被重写,这个方法默认在整个装载过程中都是同步的(线程安全的);

二:类是如何装载的
隐式装载,当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
显式装载,通过class.forname()等方法,显式加载需要的类

Java程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载

三:类加载器有哪些
1)Bootstrap Loader - 负责加载系统类
是jvm内部由c++实现的,并不继承java.lang.ClassLoader类;虚拟机的内置类加载器,用于加载java类库中的类,本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器;
主要加载%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等
2)ExtClassLoader - 负责加载扩展类
用于加载%JRE_HOME%\lib\ext目录下的jar包和class文件,其父类加载器为引导类加载器;
3)AppClassLoader - 负责加载应用类
父类加载器为扩展类加载器,加载当前应用的classpath的所有类

四:在Java中一个类的类加载器和父加载器是什么
以HotFix.java为例,当执行main方法之后

ClassLoader c  = HotFix.class.getClassLoader(); //获取HotFix类的类加载器System.out.println(c); ClassLoader c1 = c.getParent();  //获取c这个类加载器的父类加载器System.out.println(c1);ClassLoader c2 = c1.getParent();//获取c1这个类加载器的父类加载器System.out.println(c2);

输出为
AppClassLoader
ExtClassLoader
Null

可以看出HotFix是由AppClassLoader加载器加载的,AppClassLoader的Parent 加载器是 ExtClassLoader,但是ExtClassLoader的Parent为 null ,因为Bootstrap Loader是用C++语言写的,并不存在Bootstrap Loader的类实体,所以在java程序代码里试图打印出其内容时,我们就会看到输出为null。

五:综述
类装载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件;

1、装载:查找和导入Class文件
2、链接:其中解析步骤是可以选择的 (a)检查:检查载入的class文件数据的正确性 (b)准备:给类的静态变量分配存储空间 (c)解析:将符号引用转成直接引用
3、初始化:对静态变量,静态代码块执行初始化工作

六:双亲委托机制的好处

Java装载类使用“全盘负责委托机制”。“全盘负责”是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类所依赖及引用的类也由这个ClassLoder载入;“委托机制”是指先委托父类装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全方面考虑的,试想如果一个人写了一个恶意的基础类(如java.lang.String)并加载到JVM将会引起严重的后果,但有了全盘负责制,java.lang.String永远是由根装载器来装载,避免以上情况发生

七:好文分享
Java Jvm中的class loader
Java 类加载器

原创粉丝点击