Java中的ClassLoader 动态加载机制
来源:互联网 发布:js常见设计模式 编辑:程序博客网 时间:2024/04/29 13:05
前言:
Android中的动态加载机制能更好的优化我们的应用,同时实现动态的更新,这就便于我们管理我们的应用,通过插件化来减轻我们的内存以及CPU消耗,在不发布新版本的情况下能更新某些模块。
当然这里要说的并不是android中的动态加载机制,而是java中的ClassLoader动态加载我们的class,虽然android是基于Dalvik,但是先了解java中JVM怎么来加载我们的class的对于我们以后了解Android中的动态加载机制会有很大的帮助。
于是乎在网上查阅了很多关于类加载的文章了解JVM是如何通过ClassLoader来加载我们的class的。
JVM中的ClassLoadr:
java为我们提供了3个不同的ClassLoadr,分别是:
1.BootstrapClassLoader---主要负责加载java中的核心类库。是用C++代码实现的,在java虚拟机启动后初始化。
2.ExtensionClassLoader---主要负责加载java中的扩展类库。
3.AppClassLoader---用于java我们应用下的classpath中的class以及我们的jar。
JVM通过这些ClassLoadr把我们的class转换成字节码文件存贮到内存中,然后创建一个Class用特定的数据结构来封装他们,接着我们就能通过这个Class来访问其中的方法以及变量了。(这不就是我们的反射机制么,通过Class对象来获取其中的方法或者变量),当然JVM还有个验证的过程,只有通过javac编译来的class才能被ClassLoader所加载。
而ClassLoader是通过双亲委托模式来加载我们的class,就是先通过父类的ClassLoader来加载我们的class,如果父类加载失败,则通过我们的子ClassLoader来加载我们的class。(这里的父类与子类并不是集成关系)
我们可以通过URLClassLoader来动态加载我们的class也可以通过继承ClassLoader来实现我们的动态加载。而我们的ExtensionClassLoader与AppClassLoader都是继承自URLClassLoader。我这里是通过继承一个ClassLoader来实现的,通过获取Class的字节码文件来生成我们的Class,然后通过反射机制来调用我们类中的方法。
ClassLoader的扩展方法介绍:
loadClass 通过指定的二进制名来加载类(这里要把我们的包路径传过去,例如"com.ljx.test.Test")
defineClass 将byte数据转换成我们的Class类的实例
findloadClass 如果某个类加载器已经加载过这个class,则返回该类
.....还有很多这里就不一一例举了。
Test.java 先来创建需要加载的class,路径是F:Test.java,然后通过javac来生成我们的Test.class
这就是我们的Test的代码
MyClassLoader.java 通过继承ClassLoader来创建我们自己的ClassLoader,来加载Test.class
public class MyClassLoader extends ClassLoader {private byte[] results;public MyClassLoader(String pathName) {//拿到class转成的字节码文件results = loadClassFile(pathName);}public static void main(String[] args) {//初始化我们的classloader,同时拿到class所转成的字节码文件MyClassLoader classLoader = new MyClassLoader("F:\\Test.class");try {//这里要把包路径传入进去Class<?> clazz = classLoader.loadClass("com.ljx.yyy.Test");Object o = clazz.newInstance();//通过反射机制调用我们的Test.java中的printToString方法Method method = clazz.getMethod("printToString");method.invoke(clazz.newInstance());System.out.println(o.getClass().getClassLoader().toString());Method[] methods = clazz.getMethods();for (int i = 0; i < methods.length; i++) {//获取类中的方法名字String methodName = methods[i].getName();System.out.println("MethodName : " + methodName);Class<?>[] params = methods[i].getParameterTypes();for (int j = 0; j < params.length; j++) {//获取方法中的参数类型System.out.println("ParamsType : " + params[j].toString());}}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//把我们的class文件转成字节码,用于classloader动态加载private byte[] loadClassFile(String classPath) {ByteArrayOutputStream bos = new ByteArrayOutputStream();try {FileInputStream fi = new FileInputStream(classPath);BufferedInputStream bis = new BufferedInputStream(fi);byte[] data = new byte[1024 * 256];int ch = 0;while ((ch = bis.read(data, 0, data.length)) != -1) {bos.write(data, 0, ch);}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return bos.toByteArray();}@Overrideprotected Class<?> loadClass(String arg0, boolean arg1)throws ClassNotFoundException {Class<?> clazz = findLoadedClass(arg0);if (clazz == null) {if (getParent() != null) {try {//这里我们要用父加载器加载如果加载不成功会抛异常clazz = getParent().loadClass(arg0);} catch (Exception e) {//我们自定义的类加载器的父类 sun.misc.Launcher$AppClassLoader@c387f44System.out.println("getParent : " + getParent());//父类的父类 sun.misc.Launcher$ExtClassLoader@659e0bfdSystem.out.println("getParent.getparent : " + getParent().getParent());//父类的父类的父类 为null 也就是我们的Bootstrap ClassLoader 因为它是JVM生成的由C++实现;//所以拿到的是空System.out.println("getParent.getparent.getparent : " + getParent().getParent().getParent());System.out.println("父类ClassLoader加载失败!");}}if (clazz == null) {clazz = defineClass(arg0, results, 0, results.length);}}return clazz;}}先是获取我们在F:Test.class的字节码,然后通过它来得到我们的class,然后我们就能通过这个class来使用Test这个类中的方法,以下是执行main方法之后的结果:
这样,基本上就实现了从本地加载一个class到我们的项目中,是不是感觉很神奇,通过这种方式我们就能动态的加载不在我们项目中的类,例如从网上获取class的byte来动态更新我们的功能模块,或者动态加载jar中的class来实现我们要实现的功能。
代码中很大一部分是参照了网上的一些例子,当然最主要的还是为了要阐述如何通过ClassLoader来动态加载我们需要加载的类,通过ClassLoader来更好的优化我们的应用。了解了JVM如何来加载class能更好的便于我们理解Android中的动态加载技术;由于技术有限,如果上述有不正确的地方希望见谅。
0 0
- Java中的ClassLoader 动态加载机制
- java classLoader动态加载
- java classLoader动态加载
- android动态加载ClassLoader机制
- Java ClassLoader加载机制小记
- Java的ClassLoader加载机制
- Java的ClassLoader加载机制
- Java的ClassLoader加载机制
- Android动态加载基础 ClassLoader工作机制
- Android动态加载基础 ClassLoader工作机制
- Android动态加载基础 ClassLoader工作机制
- Android动态加载基础 ClassLoader工作机制
- Android动态加载基础:ClassLoader工作机制
- Android动态加载基础 ClassLoader工作机制
- Java中的类加载器(ClassLoader)及类的加载机制
- Java ClassLoader动态加载外部java代码
- java 的类加载机制(classloader)
- java 类的加载(ClassLoader)机制
- 【工具安装】-CentOS源码安装php5.6
- 关于YYModel的使用以及与MJExtension的一些比较
- java web2
- 网络视频监控系统开发系列------视频监控系统的发展历史
- 资料
- Java中的ClassLoader 动态加载机制
- SDWebImage中用到的运行时
- linux中cpuinfo信息
- Android Studio 构建项目卡在 gradle build running
- 正则表达式-理论篇
- 资料
- java web工作原理
- 资料
- 总结的iOS、mac开源项目及库,持续更新。。。。 github排名 https://github.com/trending,github搜索:https://github.com/search