【问题标题】:Runtime visibility of classes between bundles in RCP applicationRCP 应用程序中包之间类的运行时可见性
【发布时间】:2018-09-30 11:49:33
【问题描述】:

总结: 我的 OSGi 包无法在 OSGi 环境中查看运行时可用的类。

背景: 我的 RCP 应用程序将对象存储到磁盘,这涉及存储每个对象的类名。这个想法是在加载时,将使用写入磁盘的类名重新实例化对象。主AppBundle 执行存储操作。存储的对象中有其他包提供的类型的对象,例如Bundle1Bundle2

问题: 当我尝试根据存储的名称读取类信息时,虽然相同的包及其提供的类在 OSGi 运行时中,但从我的AppBundle 中看不到类信息。我已经包含了处理存储和读取的代码示意图。

public class Storage{
    transient Object[] objs = new Object[3];

    {
        // Something link the following happens dynamically during the application
        objs[0] = new AppBundleClass();
        objs[1] = new Bundle1Class();
        objs[2] = new Bundle2Class();
    }

    // Persisted to disk
    private String[] objTypes;

    public void saveToDisk(){
        objTypes = new String[objs.length];
        for (int i = 0; i < objTypes.length; i++)
            objTypes[i] = objs[i].getClass().getCanonicalName();
    }

    public void afterLoadingFromDisk(){
        objs = new Object[objTypes.length];
        for (int i = 0; i < objs.length; i++){
            Class<?> klass = Class.forName(objTypes[i]);
            // **** Throws error above ****

            objs = loadByClass(klass);      
            // Custom method that works for classes withing the app.
        }
    }
}

AppBundle 没有对 Bundle1Bundle2 的构建依赖。这个想法是应用程序的用户可以根据需要在运行时激活不同的捆绑包。

尝试的解决方案: 我怀疑问题与 OSGi 对每个捆绑包使用不同的类加载器和 AppBundle 的类加载器无法解析 Bundle1Class 有关,因为它不是通过捆绑包依赖项指定的编译时依赖项或包进口。所以,我尝试了以下方法。

Bundle1/MANIFEST.MF
   DynamicImport-Package: *
   (to allow packages from this bundle to be dynamically visible)

AppBundle/MANIFEST.MF
    Eclipse-BuddyPolicy: global
    (to allow this bundle to be able to resolve any class available in the OSGi runtime)

预期行为: Bundle1Bundle2 中的类现在应该对 AppBundle 可见。

实际行为: 奇怪的是,时不时地(相当随机地),这是有效的。但是,大多数时候,我遇到关于找不到类的错误。

【问题讨论】:

    标签: java osgi eclipse-rcp


    【解决方案1】:

    您不需要 BuddyPolicy。只需确保 Bundle1 和 Bundle2 导出包并且 AppBundle 具有DynamicImport-Package: *

    请记住,这种方法仅在每个此类包仅由一个捆绑包导出的情况下才有效。一般来说,仅通过类名来识别一个类在 OSGi 中是一种有缺陷的方法。

    更好的方法是让每个包处理它知道的类并自己进行序列化。这也将更好地匹配模块边界。

    【讨论】:

    • 谢谢,成功了!在我们从完全非模块化设计过渡时,我需要做所有这些以保持一些向后兼容性。
    【解决方案2】:

    我同意 Christian 的观点,即纯粹通过名称来识别类是问题的根源,但会提供不同的解决方案。

    在任何模块化环境中,一个类名不足以识别一个类,因为多个包可能知道同一个名称。您的应用程序当前正在保存仅附加类名的数据,因此只需将其更改为保存类名和包 ID,其中包标识由 Bundle-SymbolicNameBundle-Version 组成。

    加载时,使用Bundle-SymbolicNameBundle-Version查找匹配的Bundle对象,然后调用Bundle.loadClass(..)按名称加载类。

    您不需要导出包含持久化类的包或将此包导入到持久化框架包中。

    【讨论】:

    • 我同意类名是个问题。你知道任何基于 Java 的序列化库可以与包名称和版本一起使用吗?目前,我们依赖 Kryo,它(我认为)只使用类名来进行这种类型的存储。
    猜你喜欢
    • 2012-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 2010-09-25
    相关资源
    最近更新 更多