java中插件机制和热升级的实现方案
2015-04-01 01:14
274 查看
引言
插件式的架构可以为系统带来极高的扩展性。典型的一个例子就是eclipse。我们可以下载各种各样的插件来不断丰富eclipse的功能,而eclipse本身却不需要作任何改动。那么在java中如何实现插件机制呢?动态加载
实现插件式系统的基础是动态加载机制。所谓动态加载是指系统所要用到的字节码文件不需要添加classpath目录下,而在运行时由程序本身根据需要加载到jvm中。这种情况下相应的jar包可以放在任意位置,甚至从网络上获取。jdk中的ClassLoader类为我们提供了这一强大的特性。我们可以自定义一个子类来继承ClassLoader类,从而实现一些自定义的需求,但不要轻易就重写ClassLoader的方法,除非你对ClassLoader非常熟悉,并且有非这样做不可的需求。在本文,我们可以直接使用了jdk自带的URLClassLoader类来实现插件的动态加载。URLClassLoader的构造函数原型为:
[code]public URLClassLoader(URL[] urls, ClassLoader parent)
第一个参数为class文件或jar包的URL列表,大致可以理解为class文件的地址,该地址可以是本地磁盘地址也可以是网络地址。第二个参数为父级ClassLoader,该参数我们一般都赋值为调用者本身的ClassLoader。此处需要非常注意的是java中的类都是由classloader加载的,如果同一个class文件由不同的classloader加载,则被认为是两个class类型,他们的实例间也不能强制转换。关于ClassLoader的更详尽的讲解可以参考这篇博文: 深入分析Java ClassLoader原理
动态加载类文件需要使用URLClassLoader类的loadClass方法,其原型为:
[code]public Class<?> loadClass(String name) throws ClassNotFoundException;
其参数的含义即为我们想要加载的类的全限定名称。
先上一段示例代码:
[code] //播放器插件列表 List<Player> audioPlayers = new ArrayList<>(); //动态加载插件 URL pluginJar = new File("D:/plugins/wma-player.jar").toURI().toURL(); URLClassLoader classLoader = new URLClassLoader(new URL[]{pluginJar}, Thread.currentThread().getContextClassLoader()); Class clazz = classLoader.loadClass("org.cbqin.player.audio.WmaPlayer"); //生成插件实例 Object obj = clazz.newInstance(); if (obj instanceof Player) { //缓存到插件列表中,供之后播放时调用 audioPlayers.add((Player) obj); }
该段代码的目的是在运行时动态加载WmaPlayer类,实例化后放入播放组件列表中,从而使得播放器可以播放wma格式的音频。
从中我们不难看出插件加载的一般步骤为:
构造URLClassloader实例:通过构造方法或newInstance方法将其所能加载的URL列表设置为我们需要扫描的jar包地址列表
加载目标类文件:通过URLClassloader的loadClass方法加载目标类文件。在上述代码中为了方便理解使用了硬编码的形式,而在实际工程中一般是在jar包中添加一个plugin.xml(名字和类型均可以自由设定)文件来描述该包中需要加载的类以及插件的一些其他信息。
生成类实例 : 通过反射调用相应方法生成目标类的实例。
热替换
现在,我们已经实现了插件的动态加载。那么能否再给力一点呢,就像tomcat中,我们修改了webapp下面工程的web.xml,则tomcat可以为我们重新部署修改后的工程。答案是肯定的,热替换的基础是对类文件的实时监控。当然,同时也离不开动态加载。
目前java中的文件监控方案主要有:
jdk中的新增API WatchService API
通过JNI调用底层接口的jnotify
Apache Commons中的FileAlterationObserver
热替换的基本步骤为:
使用文件监控API监视插件目录的变化
当插件目录下的文件发生修改时,重新加载相应的插件
示例代码如下:
[code]//监控插件目录 FileAlterationObserver observer = new FileAlterationObserver("D:/plugins/"); observer.addListener(new FileAlterationListenerAdaptor() { @Override public void onFileChange(File file) { System.out.println(file.getName() + " has been changed"); //重新加载相应的jar包 try { reloadPlugin(file); } catch (Exception e) { e.printStackTrace(); } } }); //设置监控间隔 FileAlterationMonitor fileMonitor = new FileAlterationMonitor(1000, observer); // 启动监控 fileMonitor.start();
结合动态加载和文件监控API,看起来“高大上”的插件机制便被轻松的实现了。后面有空的时候会考虑再写一篇关于插件沙箱机制实现的文章,完善下这个主题。
相关文章推荐
- PHP中插件机制的一种实现方案
- php教程 插件机制在PHP中实现方案
- PHP中插件机制的一种实现方案
- PHP中插件机制的一种实现方案
- PHP中插件机制的一种实现方案
- PHP中插件机制的一种实现方案
- php教程 插件机制在PHP中实现方案
- Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结
- PHP中插件机制的一种实现方案
- PHP中插件机制的一种实现方案
- PHP中插件机制的一种实现方案
- PHP中插件机制的一种实现方案
- 插件机制在PHP中实现方案
- PHP教程:插件机制在PHP中实现方案
- [转]利用Java事件处理机制实现录制、回放功能
- 实现Java动态类载入机制
- 如何用实现.NET的插件机制
- Eclipse 3.0.1插件方案(Java版)
- 用Java事件处理机制实现录制回放功能
- 用 .NET 实现插件机制