Eclipse RCP:动态加载由另一个插件引用的库中定义的类

时间:2011-04-05 23:42:32

标签: eclipse dynamic classloader loading rcp

我有插件A,它引用了第三方JAR。我正在尝试从插件B中动态加载来自此JAR的类。

我在插件B中的类中有类似的东西:

myClass = getClass().getClassLoader().loadClass("com.foo.Bar");

如果我正在尝试加载插件A中定义的类,这可以正常工作,但是当我尝试在插件A中引用的JAR中加载类时,我得到ClassNotFoundException。

JAR位于类路径上,当我不尝试通过此类加载器动态加载时,可以访问它。

有什么想法吗?

提前致谢。

3 个答案:

答案 0 :(得分:1)

你的安装错误了。理想情况下,第三方jar应该作为插件创建(File-> New->插件来自现有的jar),暴露jar中的类。然后设置A& B依靠它。

答案 1 :(得分:1)

我认为你的解决方案的关键是以下我在另一篇文章中读到的,每个Eclipse插件都维护它自己的类加载器

所以我可以告诉你我的Eclipse(3.7)插件正在为动态加载做些什么,我不确定你是否可以适应"它满足你的需求。基本上,我的插件进行加密/解密。作为一项新增强功能,我允许用户通过FileDialog加载一个或多个Jar文件,其中每个jar文件都使用URLClassLoader加载。我创建了我的" custom" classloader,包含以下行:

this.FQCNLoader = new URLClassLoader ( getFQCNUrls(), this.getClass ().getClassLoader () );

关键是传入Eclipse插件的ClassLoader作为第二个参数......这意味着你的" custom" classloader具有Eclipse插件的CLASSPATH以及您要添加的任何URL(getter getFQCNUrls()返回URL [])。

另一个关键部分,是我保持"定制"我知道的视图中的classloader在Eclipse插件的整个生命周期中都存在。 View位于需要引用动态* .jar类的所有代码之上。

所以,你需要按照同样的方式做点什么。你的定制" classloader需要存在于pluginA和pluginB之上的类中。另外,我认为因为每个插件都有它自己的类加载器,你实际上需要构建一个" custom"类似于以下内容的类加载器:

1.) Let pluginB load dynamic *.jar/classes.  Convert into URL[].
2.) Create "custom" loader, pass in pluginB URL[] PLUS pluginA classloader.

这是我的View类中的addURL()方法,用于构建" custom" classloader ...它有点难看,因为我匆匆写了它,它重建了" custom"每次用户加载* .jar时都会加载classloader,但它在Eclipse中工作并且没有OSGi:

private int             URLCount = 0; 
private URL[]           FQCNUrls = new URL[10];
private ClassLoader     FQCNLoader = new URLClassLoader ( this.FQCNUrls );

...Lots of code...

public  void addURL ( URL theURL ) throws IOException {
    //CPTest  lclsTest = new CPTest();
    if ( getURLCount () == 0 ) { 
        getFQCNUrls()[getURLCount()] = theURL;
        setURLCount ( 1 );
    }
    else { 
        boolean lisThere = false;
        for (int i = 0; i < getURLCount(); i++) {
            if (getFQCNUrls()[i].toString().equalsIgnoreCase(theURL.toString())) {
                lisThere = true;
            }
        }
        if ( lisThere ) { 
            System.out.println ( "File URL [" + theURL.toString () + "] already on the CLASSPATH!" );
        }
        else { 
            getFQCNUrls()[getURLCount()] = theURL;
            setURLCount ( getURLCount ()+1 );
        }

    }

    // CLEAR : Null out the classloader...
    this.FQCNLoader = null;
    // BUILD/RE-BUILD : the classloader...
    this.FQCNLoader = new URLClassLoader ( getFQCNUrls(), this.getClass ().getClassLoader () );

    //try {
    //    System.out.println ( "---------------------------------------------------------------------------" );
    //    System.out.println ( "Current Working Directory.............[" + System.getProperty ( "user.dir" ) + "]" );
    //    System.out.println ( "---------------------------------------------------------------------------" );
    //    System.out.println ( "this.classes []! " );
    //    lclsTest.dumpClasses ( this.getClass ().getClassLoader () );
    //    System.out.println ( "---------------------------------------------------------------------------" );
    //
    //    System.out.println ( "---------------------------------------------------------------------------" );
    //    System.out.println ( "File URL [" + theURL.toString () + "] added! " );
    //    lclsTest.dumpClasses ( this.FQCNLoader );
    //    System.out.println ( "---------------------------------------------------------------------------" );

    //    System.out.println ( "---------------------------------------------------------------------------" );
    //    System.out.println ( "ClassLoader.getSystemClassLoader() " );
    //    lclsTest.dumpClasses ( ClassLoader.getSystemClassLoader() );
    //    System.out.println ( "---------------------------------------------------------------------------" );

    //    Class  cls = this.FQCNLoader.loadClass ( "com.lmig.RRFECF.pso.security.nonproduction.CM_RRFECF_development_securitykey" );
    //  Class  cls = Class.forName(theFQCN, false, theClsLoader);
    //    theObjectKey = ( Object )  theClsLoader.loadClass(theFQCN);


    //}
    //catch ( Exception e ) {
    //// TODO Auto-generated catch block
    //    e.printStackTrace();
    //}

    Class sysclass = URLClassLoader.class;
    try {
        Method method = sysclass.getDeclaredMethod("addURL", parameters);
        method.setAccessible(true);
        method.invoke(getFQCNLoader(), new Object[] {
            theURL
        });
    }
    catch (Throwable t) {
        t.printStackTrace();
        throw new IOException(
            "Error, could not add URL to system classloader");
    }
}
顺便说一句,我鼓励你抓住第一行中注释掉的CPTest课程,对于我深入了解不同的类加载器以及它们中的内容对我来说是非常宝贵的。我在代码中留下了Sysout行,这样你就可以看到如何在类加载器中转储所有类...

答案 2 :(得分:0)

在插件A中,确保已将jar添加到bundle manifest classpath,然后确保导出该jar中包含的包。

打开META-INF / MANIFEST-MF文件。您应该看到一个多页面编辑器。转到Runtime选项卡,然后查看Classpath部分。然后参见Exported Packages部分。然后转到Build页面并确保在Binary Build部分下检查你的jar。