【问题标题】:Enabling a OSGi/RCP plugin to load a class from another, non-dependent, plugin启用 OSGi/RCP 插件以从另一个非依赖插件加载类
【发布时间】:2012-10-09 03:32:28
【问题描述】:

我有一组三个 RCP 插件:一个是我的主要应用程序插件,另一个是计算集合,第三个是 GridGain 的包装器,其中必须从计算中创建类的实例插件。

主插件使用 ExtensionPoint 实例化从计算和 GridGain 插件中实例化类,例如:

    IExtensionRegistry registry = Platform.getExtensionRegistry();

    IExtensionPoint providerExtensionPoint = registry.getExtensionPoint(EXT_CORE_DATA_PROVIDERS);
    IConfigurationElement[] providers = providerExtensionPoint.getConfigurationElements();

    List<DataProviderFactory> dataProviders = new ArrayList<DataProviderFactory>();
    for (IConfigurationElement member : providers) {
        try {
            Object obj = member.createExecutableExtension(K_CLASS);
            if (obj instanceof DataProviderFactoryFactory) {
                DataProviderFactoryFactory factory = (DataProviderFactoryFactory) obj;
                for (Object o : factory.createProviderFactories(this, holdingProperties())) {
                    dataProviders.add((DataProviderFactory) o);
                }
            }
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    return dataProviders;

因此与其他插件没有直接依赖关系。

当 GridGain 必须从计算插件实例化类的实例时,我的问题就出现了。由于 GridGain 插件没有直接依赖于计算插件,所以它的类加载过程看不到那里的类,所以我得到了 ClassNotFoundException。

我过去曾使用RCP buddy policies 解决过类似的问题,这似乎是一个类似于您在使用 ORM 时遇到的问题。但是,“注册”策略取决于定义类的插件(在我的情况下为计算插件)依赖于实例化它们的插件(GridGain 插件)这一事实。在我的场景中,没有这样的依赖。所以添加 BuddyPolicy: 注册到 GridGain 和 RegisterBuddy: gridgain 到计算插件不起作用。

我发现让 GridGain 插件从计算插件解析类的唯一方法是将 GridGain 显式定义为对计算具有依赖性。在我看来,这不应该是必要的,应该有一种方法可以让它成为一个软依赖,如果存在计算插件,GridGain 可以从中实例化类。是否有另一种方法来模拟这种相互依赖关系,以便我的类加载问题消失?

【问题讨论】:

    标签: java osgi eclipse-rcp classloader gridgain


    【解决方案1】:

    你可以:

    1. 对计算插件的依赖是可选的。

    2. 如果您事先知道包名称,请使用 Import-Package 而不是 Require-Bundle(同样,可能是可选的)。

    3. 使用DynamicImport-Package,但在大多数情况下应避免使用。

    【讨论】:

    • 1.就是我现在正在做的。 2 对于我的目的来说听起来基本相同,我不希望这些实现被换成另一个插件,所以引用包名或包名对我来说基本上是一样的。 DynamicImport 我不熟悉,会研究它。我认为这类似于 eclipse buddy policy global 的意图?
    【解决方案2】:

    有两种安全的方法可以在不导入包的情况下从另一个包中实例化类。

    在大多数情况下,您想要一个您知道的接口的实现。对于这种情况,一种好的风格是为包中的类创建一个工厂,该类知道 impl 并发布它,例如使用 OSGi 服务。然后可以在工厂内部使用 new 实例化该类。

    另一种方法是使用知道 impl 的 bundle 的类加载器。在这种情况下,您必须使用允许检索其他包的类加载器的接口。然后你可以通过它的名字来加载这个类。

    【讨论】:

    • 我认为第一种方法与此无关,因为 GG 对保留对实例化对象的引用不感兴趣,它只负责实例化它们并将它们传递给其余的应用程序。第二个建议相当于有一个可选的依赖项,对吧? GG 插件仍然需要特别注意计算插件。
    • 我是否正确,您希望使用来自计算和 GridGain 的工厂填充 DataProviderFactories 的动态列表?如果是,那么服务方法可能是理想的。只需让计算和 GridGain 在它们的 Activator 中创建它们的工厂,并将它们注册为 OSGi 服务。然后你bundle就可以得到DataFactory接口的服务列表,简单的过一遍。这样您就不再需要扩展点了。
    • 这不太对,也许我最初的问题措辞不好。主插件通过 ExtensionPoints 实例化 DataProviderFactories。 Gridgain 插件会接收到一个指令,通过名称(例如,'com.company.DataProviderFactoryImpl)实例化一个类的实例。在 GridGain 产品内部(即不在 OSGi 或 RCP 感知代码中),调用 Class.forName(name),但由于插件类加载器不知道声明 com.company.DataProviderImpl 的计算插件而失败.
    • 在这种情况下,这是 Gridgain 产品中的问题。如果您对他们有任何影响,请尝试让他们提供一个 api,您可以在其中提供类加载器和类名。然后就很容易了。在这种情况下,DynamicImport-Package 可能是另一种解决方法。您可以将它用于包含 GridGain jar 的包。所以它会看到所有的类。问题只是你对它看到的东西没有太多控制。所以我认为这只是最后的手段。
    【解决方案3】:

    GridGain 插件应该有某种方式依赖于您的计算插件。如果您不定义任何依赖项,GridGain 将无法访问计算类。我可以想到这一点,创建另一个具有通用接口的插件(基本插件)并使 GridGain 和计算依赖于基本插件。在计算插件中为您在基本插件中定义的接口公开声明性服务。

    在GridGain插件中,使用osgiServiceTracker等待Calculations插件中暴露的服务。

    【讨论】:

    • 在这种情况下,尽管 GridGain 不需要与实现交互,但只需在解组期间实例化它们即可。这更像是 Hibernate 需要实例化业务对象,然后将它们传递给应用程序。
    猜你喜欢
    • 2015-02-18
    • 2013-01-04
    • 2017-06-25
    • 1970-01-01
    • 2012-09-27
    • 2013-09-26
    • 2018-07-15
    • 2021-04-09
    • 1970-01-01
    相关资源
    最近更新 更多