转载自:最新内容及最清晰格式请见 http://www.trinea.cn/android/java-loader-common-class/

本文主要介绍 ClassLoader 的基础知识,ClassLoader 如何动态加载 Jar,ClassLoader 隔离问题及如何加载不同 Jar 中的公共类。

本文工程开源地址见:Java Dynamic Load Jar@Github,Clone 以后直接以 Java Application去运行 java-dynamic-loader-host 工程即可。

其实本文只是 Android 插件化的一个引子,做过 Android 插件化的同学,可以试试对于 Android Support 包中的 FragmentActivity 和 ActionBarActivity 怎么像一般的 Activity 一样被代理,挺有意思。

1. ClassLoader 的基础知识
无论是 JVM 还是 Dalvik 都是通过 ClassLoader 去加载所需要的类,而 ClassLoader 加载类的方式常称为双亲委托,ClassLoader.java 具体代码如下:

protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(className); if (clazz == null) {
try {
clazz = parent.loadClass(className, false);
} catch (ClassNotFoundException e) {
// Don't want to see this.
} if (clazz == null) {
clazz = findClass(className);
}
} return clazz;
}

从上面加载类的顺序中我们可以知道,loadClass 会先看这个类是不是已经被 loaded 过,没有的话则去他的 parent 去找,如此递归,称之为双亲委托。

2. 动态加载 Jar
Java 中动态加载 Jar 比较简单,如下:

URL[] urls = new URL[] {new URL("file:libs/jar1.jar")};
URLClassLoader loader = new URLClassLoader(urls, parentLoader);

表示加载 libs 下面的 jar1.jar,其中 parentLoader 就是上面1中的 parent,可以为当前的 ClassLoader。

3. ClassLoader 隔离问题
大家觉得一个运行程序中有没有可能同时存在两个包名和类名完全一致的类?
JVM 及 Dalvik 对类唯一的识别是 ClassLoader id + PackageName + ClassName,所以一个运行程序中是有可能存在两个包名和类名完全一致的类的。并且如果这两个”类”不是由一个 ClassLoader 加载,是无法将一个类的示例强转为另外一个类的,这就是 ClassLoader 隔离。 如 Android 中碰到如下异常

android.support.v4.view.ViewPager can not be cast to android.support.v4.view.ViewPager

当碰到这种问题时可以通过 instance.getClass().getClassLoader(); 得到 ClassLoader,看 ClassLoader 是否一样。

4. 加载不同 Jar 包中公共类
现在 Host 工程包含了 common.jar, jar1.jar, jar2.jar,并且 jar1.jar 和 jar2.jar 都包含了 common.jar,我们通过 ClassLoader 将 jar1, jar2 动态加载进来,这样在 Host 中实际是存在三份 common.jar,如下图:

我们怎么保证 common.jar 只有一份而不会造成上面3中提到的 ClassLoader 隔离的问题呢,其实很简单,有三种方式:
第一种:我们只要让加载 jar1 和 jar2 的 ClassLoader 的 parent 为同一个 ClassLoader,并且该 ClassLoader 加载过 common.jar,通过上面 1 中我们知道根据双亲委托,最后都会首先被 parentClassLoader加载。

第二种:我们重写 jar1 和 jar2 的 ClassLoader,在 loadClass 函数中我们先去某个含有 common.jar 的 ClassLoader 中 load 即可,其实就是把上面的 parentClassLoader 换掉了而已。

第三种:在生成 jar1 和 jar2 时把 common.jar 去掉,只保留 host 中一份,以 host ClassLoader 为 parentClassLoader 即可。
具体可见代码:JarClassLoader

大家测试后会发现对于 Java 是正常的,而方式一和方式二对于 Android 却失败,具体原因下次再说吧

Java ClassLoader基础及加载不同依赖 Jar 中的公共类的更多相关文章

  1. Java ClassLoader基础及加载不同依赖 Jar 中的公共类(转)

    http://www.iteye.com/topic/1135259 http://www.trinea.cn/android/java-loader-common-class/ http://www ...

  2. Java --ClassLoader创建、加载class、卸载class

    一.java提供了三种ClassLoader对Class进行加载: 1.BootStrap ClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库 ...

  3. 03 Java 虚拟机是如何加载 Java 类的

    Java 引用类型 Java 中的引用类型细分为四种:类,接口,数组类和泛型参数. 因为泛型参数会在编译过程中被擦除,所以 Java 虚拟机实际上只有前三种.数组类是由 Java 虚拟机直接生成的,其 ...

  4. 《深入理解Java虚拟机》- Java虚拟机是如何加载Java类的?

    Java虚拟机是如何加载Java类的?  这个问题也就是面试常问到的Java类加载机制.在年初面试百战之后,菜鸟喜鹊也是能把这流程倒背如流啊!但是,也只是字面上的背诵,根本就是像上学时背书考试一样. ...

  5. Java安全之动态加载字节码

    Java字节码 简单说,Java字节码就是.class后缀的文件,里面存放Java虚拟机执行的指令. 由于Java是一门跨平台的编译型语言,所以可以适用于不同平台,不同CPU的计算机,开发者只需要将自 ...

  6. 自定义ClassLoader,用于加载用户JAR包

    最近在考虑C/S结构程序的软件自动升级的实现方式,比如QQ.飞信等都自动升级的功能. 自动升级模块虽然还没有编码完成,但是思路还是比较清晰的. 自动升级过程中,升级文件的JAR包是专门加载到程序中去的 ...

  7. Java 类加载器及加载Class字节码

    参考来源:http://www.cnblogs.com/fingerboy/p/5456371.html       java笔记--理解java类加载器以及ClassLoader类 参考来源:htt ...

  8. Java 类中各成分加载顺序 和 内存中的存放位置

    参加一个笔试,有一个关于类的静态代码块.构造代码块.构造函数的执行顺序的问题.不太清楚,网上百度了一下.在这里记录一下. 一.什么时候会加载类?使用到类中的内容时加载:有三种情况1.创建对象:new ...

  9. 根据配置文件加载js依赖模块(JavaScript面试题)

    面试题目 根据下面的配置文件 module=[ {'name':'jquery','src':'/js/lib/jquery-1.8.3.js'}, {'name':'swfobject','src' ...

随机推荐

  1. 自定义ToolBar之一

    其实已经有很多大神写过这方面的文章了,不过我比较蠢吧,老有一些地方看不懂的,翻了很多关于Toolbar方面的文章和视频,这儿总结一下.  参考资料:youtube:slidenerd 阶段一 自定义配 ...

  2. ODBC连接发生错误:未发现数据源名称并且未指定默认驱动程序

    程序在使用ODBC方式连接数据库时发生错误: ERROR [IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序. 什么原因造成的呢? 本人使用&l ...

  3. log4j介绍以及使用教程

    一.介绍 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接 口服务 器.NT的事件记录器.UNIX Syslog ...

  4. ssh-keygen详解

    先来一段google wiki关于ssh key的解释,对应的连接为:https://wiki.archlinux.org/index.php/SSH_keys_(%E7%AE%80%E4%BD%93 ...

  5. auto(c++11)

    C++primer 第五版,第三章出现了此段程序,求解读附源码:代码1:#include<iostream>#include<string>using namespace st ...

  6. C++面向对象基础知识

    多态是为了接口重用,封装和继承是为了代码重用 子类重新定义父类虚函数的方法叫做继承,不是重载! 一.基本概念 对于C++中经常出现的函数名称相同但是参数列表或者返回值不同的函数,主要存在三种情况: 1 ...

  7. 写了个简单的pdo的封装类

    <?php class PD { //造对象 public $dsn = "mysql:dbname=test2;host=localhost"; //数据库类型,数据库名和 ...

  8. Delphi数组

    参考:http://www.cnblogs.com/huangjacky/archive/2009/12/21/1628833.html 数组就是一堆相同特性数据的一个组合,也就是每个元素的类型必须是 ...

  9. 玩转SSRS第十篇---自定义代码

    提到SSRS 那么就不得不提一下自定义代码的功能,通过自定义代码,有时候可以解决一些比较复杂的问题,比如将让指定的数据行应用指定的属性值.此篇将演示如何通过简单结构的自定义代码进行报表样式的基本设计. ...

  10. HDU5489 Removed Interval(动态规划)

    一个长度为n的序列,删除任意长度为l的连续子序列后,求剩下的序列的最长公共子序列. 先求出以第i个元素为开始的LIS的长度,再一次循环,对所要求的结果更新 #include<iostream&g ...