前段时间有师弟师妹问我,java能不能实现像我们生活中很多客户端软件(像QQ客户端)那样的自动更新,我想了一下,猜想可以用java的动态类加载机制加以实现,下面先介绍下java的动态类加载机制吧······
首先,java类加载类加载中有一个重要特点就是懒加载(lazy load),即只有当要用到这个类时,系统才会加载这个类。java类是由类加载器负责加载的,ClassLoader类就是一个基本的类加载器,用java语言写的,可以通过继承它实现类加载的自定义,提升程序的灵活性。
JVM中可以有多个类加载器存在,他们形成一种树状结构,如图:
位于根部的类加载器叫起始类加载器(The Primordial Class Loader),是用C语言写的JVM的一个部分,负责实现本地加载类的基本功能。在java语言中,除了起始类加载器外,其他类加载器都是通过继承ClassLoader类形成的,如URLClassLoader。
每个类都可以用来加载类,而且同一个类可以在不同的类加载器中多次加载,但是在一个加载器上只能加载一次。这是因为当类加载器加载一个类时会先检查这个类是否被本类加载器加载过,当且仅当第一次加载时会产生实例并生成返回保存这个类对象的句柄。否则,直接返回句柄。
摘抄张敦化在一篇文章中曾用于说明这个问题的代码:
这里他用了委托机制来加载类,首先执行findLoadedClass方法,这个方法功能就是检查在本类加载器中方法是否被加载过,没有就交给父类加载器,依次类推,直到起始类加载器如果还不能加载,就自己加载。自己加载使用findClass方法,在ClassLoader中,这个方法仅仅抛出一个类不能发现的异常,因此我们在自定义这个类加载器时,应该覆盖这个方法。方法最后还判断输入参数resolve是否为真,如果为真则执行resolveClass方法,这个方法的功能就是溶解类(resolve),即加载完这个类后要加载与这个类相关联的类。
总结一下,java中有三种加载类的方法:
a.直接调用一个ClassLoader实例的loadClass方法来加载类,那么这个类的类加载器就是被调用的ClassLoader实例;
b.利用Class类的forName静态方法来加载一个类,这个方法既可以指定一个类加载器,也可以不指定。当不指定时,其默认的类加载器就是执行ClassLoader方法的类相应的类对应的类加载器;
c.用new关键字创建一个对象(这个类以前还没有加载)或执行一个类的静态方法,系统就会用默认的类加载器加载该类。
JVM加载类有以下原则:
a.加载第一个类是java应用时,用URLClassLoader;
b.加载第一个类是javaapplet应用时,用AppleClassLoader,具有一些安全性限制;
c.系统会使用同个类加载器加载关联的类。
基于以上特点,对自动更新,我的设想是:当运行客户端需要加载某个类时,就先到服务器上检查,当发现本地存放版本比服务器旧时就从网络下载加载新版本类文件。若不是,加载本地类文件。