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

发布于 2024-10-30 18:46:52 字数 337 浏览 4 评论 0原文

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

我从插件 B 中的类中得到类似的内容:

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

如果我尝试加载插件 A 中定义的类,则效果很好,但是当我尝试加载插件 A 中引用的 JAR 中的类时,我得到了 ClassNotFoundException。JAR

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

有什么想法吗?

提前致谢。

I have plug-in A which references a 3rd party JAR. I'm trying to dynamically load classes from this JAR from plug-in B.

I have something like this from a class in plug-in B:

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

This works fine if I'm trying to load classes that are defined in plug-in A, but I get ClassNotFoundException when trying to load classes in the JAR referenced in plug-in A.

The JAR is on the class-path and is accessible when I'm not trying to dynamically load via this class loader.

Any ideas?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

虐人心 2024-11-06 18:46:52

你的设置错了。理想情况下,第 3 方 jar 应该创建为插件(文件 -> 新建 -> 现有 jar 中的插件),公开 jar 中的类。然后将 A 和 A 都设置为B 依赖它。

You got your setup wrong. Ideally the 3rd party jar should be created as a plugin (File->New->Plugin from existing jars), exposing the classes in the jar. Then set both A & B to depend on it.

[旋木] 2024-11-06 18:46:52

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

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

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

关键是将 Eclipse 插件的 ClassLoader 作为第二个参数传递...这意味着您的“自定义”类加载器具有 Eclipse 插件的 CLASSPATH 以及您要添加的任何 URL( getter getFQCNUrls() 返回一个 URL[])。

另一个关键部分是我在视图中维护“自定义”类加载器,我知道该视图在 Eclipse 插件的整个生命周期中都会持续存在。视图位于需要引用动态 *.jar 类的所有代码之上。

因此,您需要按照同样的思路做一些事情。您的“自定义”类加载器需要位于pluginA 和pluginB 之上的类中。另外,我认为因为每个插件都有自己的类加载器,所以您实际上需要构建一个“自定义”类加载器,它执行如下操作:

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

这是我的 View 类中的 addURL() 方法,它构建了“自定义”类加载器“类加载器...它有点难看,因为我匆忙编写了它,并且每次用户加载 *.jar 时它都会重建“自定义”类加载器,但它确实可以在 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 行,以便您可以了解如何转储类加载器中的所有类...

I think the key to your solution is the following I read in another post, Each Eclipse Plugin maintains it's own classloader.

So I can tell you what my Eclipse (3.7) plugin is doing for dynamic loading, I'm not sure if you can "fit" it into your needs. Basically, my plugin does encryption/decryption. As a new enhancement, I allow the user to load one or more Jar files via a FileDialog, where each jar file is loaded using a URLClassLoader. I create my "custom" classloader with the following line :

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

The key was to pass in the Eclipse plugin's ClassLoader as the second argument...This means your "custom" classloader has the CLASSPATH of the Eclipse plugin plus whatever URLs you are adding (the getter getFQCNUrls() returns a URL[]).

The other key piece, was I maintain the "custom" classloader in a View that I know persists for the entire life of the Eclipse plugin. The View resides above all code that needs to reference the dynamic *.jar classes.

So, you'll need to do something along the same lines. Your "custom" classloader would need to live in a Class above both pluginA and pluginB. Also, i would think because each plugin has it's own classloader, you're actually going to need to build a "custom" classloader that does something like the following :

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

Here is the addURL() method in my View class that builds the "custom" classloader...it's a little ugly, because I wrote it in a hurry and it rebuilds the "custom" classloader each time the user loads a *.jar, but it does work in Eclipse and without 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");
    }
}

BTW, I encourage you to grab that CPTest class commented out in the first line, it was invaluable to me on getting insight into the different classloaders and what was in them. I left the Sysout lines in the code so you can see how to dump all the classes in a classloader...

如若梦似彩虹 2024-11-06 18:46:52

在插件 A 中,确保已将 jar 添加到捆绑清单类路径中,然后确保导出该 jar 中包含的包。

打开 META-INF/MANIFEST-MF 文件。您应该会看到一个多页面编辑器。转到运行时选项卡并查看类路径部分。然后查看导出的包部分。然后转到“构建”页面并确保在“二进制构建”部分下检查了您的 jar。

In plugin A, make sure that you've added the jar to bundle manifest classpath and then make sure to export the packages contained in that jar.

Open META-INF/MANIFEST-MF file. You should see a multi-page editor. Go to Runtime tab and see Classpath section. Then see Exported Packages section. Then go to Build page and make sure that your jar is checked under Binary Build section.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文