Java动态加载与插件开发研究
Java动态加载与插件开发研究
摘要:本文首先研究了Java语言的动态加载方式和实现插件化的方法,并以支持不同音频格式的音乐播放器为例展示了Java插件的开发步骤。本文所展示的Java插件的开发方法和步骤具有一般性指导意义,可以很好地解决新功能植入或着功能模块定制问题。
关键词:动态加载;Java 插件;功能植入;模块定制
1 概述
软件项目开发经常会遇到这样的情况发生,就是当项目开发结束并交付使用后,需要增加一些新功能。我们通常希望在不改变原有应用程序代码的前提下,将新增加的功能植入到系统中。
还有一种情况就是针对同一个功能模块,不同用户会要求不同的具体实现。例如,呼叫中心坐席软件中的来电弹屏功能,不同用户可能要求展示客户信息的方式不一样,信息来源不一样,有的甚至要求完成一些额外的功能。这就是所谓的功能模块定制。
不管是新功能植入,还是功能模块定制,我们都可以使用插件化技术来解决。新增加的功能模块,或者被定制的功能模块,被
称为插件。插件化技术带来的好处直接体现为降低了模块之间的耦合性,便于各个模块的独立维护,方便和加快整个项目的维护更新。
Java语言的动态加载技术完美的支持了插件化开发。本文首先研究了Java语言的动态加载方式和实现插件化的方法,并以支持不同音频格式的音乐播放器为例展示了Java插件的开发步骤。
2 Java动态加载并实例化的几种方式
Java程序运行时是需要把类加载到内存的。Java类的加载方式有两种:隐式加载和显式加载。隐式加载是通过new 的方式,如:Person person=new Person(),在类初始化时
由Java虚拟机根据相应的类加载器(ClassLoader)将类载入[1]。显式加载则是程序员在代码中显式地利用某个类加载器将类载入。显示加载并实例化类又可以通过下面两种方法:
2.1 使用Class类[1]
在Java中通过Class类的静态方法forName()可以动
态加载一个指定的类(需要提供类的完整名字),然后调用newInstance()就可以构造一个该类的实例,例如:String className = "com.abc.Person";
Person person=Class.forName(className).newInstance ();
这个功能对于相同接口的不同实现具有重大意义。我们
可以定义一个接口,然后提供好几个该接口的实现类,用户通过修改配置文件来指定实际使用哪一个实现类,然后在源码中读取配置文件,就可以构造一个指定实现类的实例而不用每次修改源码。通过这种方法,系统只要关心接口的定义,用户只要进行配置文件的设置,就完成了同一功能不同实现的任意切换。
2.2 使用ClassLoader
这种方法需要首先获得ClassLoader,然后通过ClassLoader的loadClass ()方法动态加载一个指定的类。Java 提供了以下三种途径得到ClassLoader:
?使用系统类加载器:ClassLoader.getSystemClassLoader ();
?使用当前类加载器:this.getClass.getClassLoader();
?使用当前线程类加载器:Thread.currentThread
().getContextClassLoader();
下面的代码片段展示了如何使用系统类加载器装载并
实例化的过程:
ClassLoader cloader = ClassLoader.getSystemClassLoader ();
Class cls = cloader.loadClass("com.abc.Person");
Person person = (Person)cls.newInstance();
需要注意的是:系统类加载器处理-classpath下的类加载
工作,它适合于简单的命令行应用,如果是EJB,或java Web 应用,请使用其他的类加载器。
3 Java 插件的开发(Java Plugin development)
下面考虑这样一种应用场景:现有用Java语言编写的主程序,要求第三方开发人员编写扩展功能。约定第三方开发人员开发的类必须包含一个实现某已知接口的类,名称不限。要求第三方开发的类打成jar包,与主程序分开发布。jar包放在主程序安装目录下的plugins子目录下,主程序启动时动态加载jar 包中的类。
这是典型的Java插件技术在实际应用中的体现。为了开发java插件,java提供了URLClassLoader解决从jar文件中
动态加载类。URLClassLoader是ClassLoader的子类,它用
于从指定的jar文件和目录的URL搜索路径加载类和资源,即,通过URLClassLoader就可以加载指定jar中的类到内存
中[2]。下面的代码片段说明了这一过程:
// 动态加载jar包
String url_str = "file:C:\PluginDemo\plugins\WMAPlayer.jar";
URL[] urls = new URL[1];
urls[0] = new URL(url_str);
URLClassLoader loader = new URLClassLoader(urls);
//从加载器中加载插件类,然后实例出一个对象
Class<?> c = loader.loadClass ("com.abc.plugin.WMAPlayer");
北大青鸟推荐:Java精选笔试题(含答案解析)
北大青鸟推荐:Java精选笔试题(含答案解析)如果你是计算机专业出生,但是还没有找到工作的话,你就得补补技术了,一些关于面试、笔试的题要多刷一刷。有可能你知道答案,但是由于语言组织能力有所欠缺,所以面试官的印象不是很好,下面分享一些Java精选的鄙视题,希望对面试这者有帮助。 1,volatile关键字是否能保证线程安全?() 答案:否 volatile关键字用在多线程同步中,可保证读取的可见性,JVM只是保证从主内存加载到线程工作内存的值是最新的读取值,而非cache中。但多个线程对volatile的写操作,无法保证线程安全。 假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值,在线程1对count进行修改之后,会write到主内存中,主内存中的count变量就会变为6;线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6;导致两个线程及时volatile关键字修改之后,还是会存在并发的情况。 2,下面哪个流类属于面向字符的输入流( ) A、BufferedWriter B、FileInputStream C、ObjectInputStream D、InputStreamReader 答案:D Java的IO操作中有面向字节(Byte)和面向字符(Character)两种方式。
面向字节的操作为以8位为单位对二进制的数据进行操作,对数据不进行转换,这些类都是InputStream和OutputStream的子类。 面向字符的操作为以字符为单位对数据进行操作,在读的时候将二进制数据转为字符,在写的时候将字符转为二进制数据,这些类都是Reader和Writer的子类。 3,Java能不能不通过构造函数创建对象() A、能 B、不能 答案:A Java创建对象的几种方式: (1) 用new语句创建对象,这是最常见的创建对象的方法。 (2) 运用反射手段,调用https://www.360docs.net/doc/b83465203.html,ng.Class或者https://www.360docs.net/doc/b83465203.html,ng.reflect.Constructor类的newInstance()实例方法。 (3) 调用对象的clone()方法。 (4) 运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法。 (1)和(2)都会明确的显式的调用构造函数;(3)是在内存上对已有对象的影印,所以不会调用构造函数;(4)是从文件中还原类的对象,也不会调用构造函数。 4,下列哪个叙述是正确的() A.子类继承父类的构造方法。 B.abstract类的子类必须是非abstract类。 C.子类继承的方法只能操作子类继承和隐藏的成员变量。 D.子类重写或新增的方法也能直接操作被子类隐藏的成员变量。 答案:C 子类是不继承父类的构造方法的,而是必须调用其父类的构造方法。
Java API 试题
永隆 JAVA笔试题 一、选择题 1、关于Java 类的加载过程,下面哪些描述是正确的() A、在 Java 中,有四种类型的类加载器:BootStrapClassLoader、ExtClassLoader、AppClassLoader 以及用户自定义的ClassLoader。//Extension ClassLoader, System ClassLoader+用户自定义的classloader B、使用 new 关键字创建类实例时,其实就显示地包含了类的加载过程 C、在 Java 中,类的实例化流程分为两个部分:类的加载和类的实例化。类的加载又分为显式加载和隐式加载。 D、Class.forName 来加载类时,是通过 ExtClassLoader进行加载的。 //system classLoader 加载 2、关于HashMap的实现机制,下面哪些描述是正确的() A、HashMap中key-value 当成一个整体进行处理,系统总是根据数组的坐标来获得key-value 的存储位置。//没有存储顺序,无下标之说! B、HashMap基于哈希表的 Map 接口的实现,允许使用 null 值和 null 键。 C、如果HashMap中,如果Key的hash相同的话,HashMap将会出错。//会替换相应的value D、HashMap每次容量的扩增都是以2的倍数来增加。//大约获得2倍的桶数! 3、下面的代码执行输出正确的是() 1. public class test( 2. public int aMethod()[ 3. static int i=0; 4. i++; 5. return I; 6. ) 7. public static void main (String args[]){ 8. test test = new test(); 9. test.aMethod(); 10.int j = test.aMethod(); 11.System.out.printIn(j); 12.] 13.} A. 编译错误 B. 编译成功,打印出是“0” C. 编译成功,打印出是“1” D. 编译成功,打印出是“2” A 4、如何获取下面表单 select