Java ClassLoader基础及加载不同依赖 Jar 中的公共类

本文主要介绍 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 具体代码如下:

Java


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17


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 比较简单,如下:

Java


1

2


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 中碰到如下异常

Java


1


java.lang.ClassCastException: 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 却失败,具体原因下次再说吧。

时间: 2024-09-13 12:09:28

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

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

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

jvm-java ClassLoader怎么手动加载2个相互引用的类

问题描述 java ClassLoader怎么手动加载2个相互引用的类 public class A{ private B b; } public class B{ private A a; } 程序中只有这2各类的class文件的2进制数据(2个byte[]),怎么使用classloader加载这2个类呢. 因为涉及到了A类需要B类 B类需要A类,如果使用简单的defineClass会出ClassNotFoundException异常.

查看java进程加载了哪些jar包。

问题描述 查看java进程加载了哪些jar包. 各位大神帮帮忙.如何查看一个java进程加载了哪些jarbao包?有没有比较好的工具. 解决方案 Java ClassLoader加载.jareclipse java EE无法加载java基础的jar包 解决方案二: 进程加载了哪些jar包?在项目里面应该可以直接看到了吧? 解决方案三: 这个不应该在进程里看吧?应该在项目中看的 解决方案四: 项目开发时都是放在web-lib目录下的,outline视图模式下可以很清楚的看到啊. 如果是maven项

JAVA类库的提前加载

在JAVA运行的时加载jar包类库 要是有相同的包路径,相同的类名字出现,那么JVM是否 会报告错误呢? 当然不会! JVM只会加载最早的出现的CLASS 首先JVM会加载 自己默认的包 然后加载 EXT目录下面的所有JAR 再到 classpath 那么 现在有2个 JAR 分别是 kj021320.jar summer.jar 里面都有包路径cn.isto 同样有 类Jcrack.class 那么 JVM就会看哪个 类先加载到VM中就用哪个!后面读进来的 如果路径名字一样 就会丢弃! 想到以

请问:用java代码mysql如何加载到memcached中?谢谢!!

问题描述 请问:用java代码mysql如何加载到memcached中?谢谢!! 请问:用java代码mysql如何加载到memcached中?谢谢!! 解决方案 你应该是想java调用数据库等访问mysql获取到数据,然后放入memcached等做缓存.

java 利用java反射机制动态加载类的简单实现_java

如下所示: ////////////////// Load.java package org.bromon.reflect; import java.util.ArrayList; import java.util.List; public class Load implements Operator { @Override public List<?> act(List<?> params) { // TODO Auto-generated method stub List<

Java连接数据库,成功加载SQL驱动程序,但数据库连接失败

问题描述 Java连接数据库,成功加载SQL驱动程序,但数据库连接失败 import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; public class T2 { public static void main(String[] args) { try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver&quo

背水一战 Windows 10 (63) - 控件(WebView): 基础知识, 加载 html, http, https, ms-appx-web:///, embedded resource, ms-appdata:///, ms-local-stream://

原文:背水一战 Windows 10 (63) - 控件(WebView): 基础知识, 加载 html, http, https, ms-appx-web:///, embedded resource, ms-appdata:///, ms-local-stream:// [源码下载] 背水一战 Windows 10 (63) - 控件(WebView): 基础知识, 加载 html, http, https, ms-appx-web:///, embedded resource, ms-ap

mysql-请问:用java代码把不同的excel形式加载到MySQL数据库中(循环判断空就停止)?谢谢!

问题描述 请问:用java代码把不同的excel形式加载到MySQL数据库中(循环判断空就停止)?谢谢! 用java代码把不同的excel形式加载到数据库中(循环判断空就停止)?谢谢! 解决方案 JAVA 导入导出EXCEL文件操作http://blog.csdn.net/thl331860203/article/details/6333397 下载源代码http://download.csdn.net/source/3205282 解决方案二: 你是讲excel中的数据导入到mysql中么.