Java程序所依赖的类库JAR包,可以在开发时的时候添加的classpath中.但有时候,在开发时无法确定所依赖JAR包,或者这些JAR经常改变,这要求程序具有在发布后能动态加载JAR包的功能.
一般的Java程序,可以使用URLClassLoader这个类的addURL方法来实现该功能.
详细可以参考: http://buliedian.iteye.com/blog/993361
但RCP程序无法使用这个办法加载.
原因
因为RCP的程序是运行在OSGi框架之下,而用户开发的程序是由一个叫DefaultClassLoader的类来加载的,而不是一般的URLClassLoader.DefaultClassLoader类并没有可以直接加载JAR的接口提供.
如果用户自己new 一个URLClassLoader来加载JAR包,是可以加载到新的类, 但由于跟主程序的Classloader不是从属关系,两者之间的class并不能相互引用,也就说这个加载进来的JAR包一定是要完全独立的,不能依赖于主程序的类.
解决
这个问题的正规解决方法是把这些第三方的JAR包独立发布成插件,在RCP主程序插件中定义对该插件的依赖.但这个方法的问题是,每次有新的JAR需要跟新的话,我们都必须重新发布这个JAR包插件,并更新到RCP程序中.
详细请参考:http://blog.youkuaiyun.com/soundyrose/article/details/5608953
另外的解决方法是利用RCP的Fragment概念.
Fragment原来是作为Plugin的补丁更新来开发和发布的.而DefaultClassLoader下有一个ClasspathManager,它提供了attachFragment的接口供OSGi框架来为Plugin加载Fragment.
所以该方法的具体做法是调用这个attachFragment方法把第三方jar加载进去pluyin中.这就相当于为plugin加载了一个没有实际内容,只有外部JAR的fragment.
代码如下
/*取得当前DefaultClassLoader的ClasspathManager*/
ClasspathManager manager = ((DefaultClassLoader) DataFileManager.class.getClassLoader()).getClasspathManager();
/* 准备第三方JAR的路径列表 */
ArrayList<String> paths = new ArrayList<String>();
paths.add("external: D:/external.jar");
/* 把这些JAR的路径作为plugin的fragment在运行时加入到plugin中去. */
manager.attachFragment(manager.getBaseData(),null,paths.toArray(new String[paths.size()]));
*其中如果JAR文件已经打包在RCP的Plugin JAR中,那么可以用相对路径引用.如果JAR在RCP的Plugin JAR外,需要绝对路径时,必须在前面加"external:" 作为标识.
这个方法的虽然并不是常规的方法,但可以提供很灵活的加载手段.