使用 Guice/Peaberry 进行 osgi 声明式服务

Posted

技术标签:

【中文标题】使用 Guice/Peaberry 进行 osgi 声明式服务【英文标题】:Using Guice/Peaberry for osgi declarative services 【发布时间】:2015-04-12 21:39:20 【问题描述】:

我想解决以下问题,需要建议,最好的解决方案是什么。

我有一个包 A,其中定义了服务接口 X。包 B 提供 X 的服务实现并将实现贡献给工具。 A 和 B 使用 Google Guice 和 Peaberry 来配置对象的设置。

我可以使用两种可能性来贡献服务实现:

    使用 Eclipse 扩展: 在这个解决方案中,我可以使用 Peaberry 的 GuiceExtensionFactory 机制来使用 Guice 创建服务实现,因此可以注入实现所需的东西。这里的缺点是,在定义扩展点的包中,我需要用于解析扩展的样板代码,因为据我所知,无法将扩展注入到使用扩展的类中。 如下所示:
<extension point="A.service.X">
  <xservice
    ...
    class="org.ops4j.peaberry.eclipse.GuiceExtensionFactory:B.XImpl"
    .../>
</extension>
<extension
  point="org.ops4j.peaberry.eclipse.modules">
  <module
    class="B.XModule">
  </module>
</extension>

但我需要这样的样板代码:

private List<X> getRegisteredX() 
    final List<X> ximpls = new ArrayList<>();
    for (final IConfigurationElement e : Platform.getExtensionRegistry().getConfigurationElementsFor(               X_EXTENSION_POINT_ID)) 
        try 
            final Object object = e.createExecutableExtension("class"); //$NON-NLS-1$
            if (object instanceof X) 
                ximpls.add((X) object);
            
         catch (final CoreException ex) 
            // Log
        
    
    return ximpls;

    使用 OSGI 服务: 我的主要问题是确保服务已注册。我希望延迟加载捆绑包,因此至少需要访问捆绑包的类之一。使用 Peaberry 以编程方式注册服务是有问题的,因为没有人要求提供捆绑包的类。解决方案是将服务作为声明式服务提供,但我不知道以某种方式创建服务实现的方法,即我可以使用 Guice 注入所需的对象。

所以我有一些问题:

    到目前为止,有没有什么我不知道的东西可以实现在扩展点通用读取扩展所需的代码并允许使用扩展将扩展注入到类中? 是否有办法确保即使使用标准 Peaberry 机制添加服务(即在请求服务时激活捆绑包)也能提供服务? 有没有像 GuiceExtensionFactory 这样的声明式服务的方法,这样服务实现的创建可以通过 bundle 的注入器来完成? 看起来像:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Ximpl">
   <implementation class="some.generic.guiceaware.ServiceFactory:B.Ximpl"/>
   <service>
      <provide interface="A.X"/>
   </service>
</scr:component>

总之,我想要一个由 Guice 生成的服务实现,并且我希望使用该服务将服务实现简单地注入到类中,而无需大量样板代码。有没有人解决这个问题?

抱歉,我在网上搜索了很长时间,至今没有找到解决方案。

感谢和最好的问候, 拉尔斯

【问题讨论】:

【参考方案1】:

我找到了一个解决方案,但由于我没有经过大量尝试和思考就没有找到它,所以我想我在这里分享它。从我在帖子中提到的选项中,我的解决方案使用第一个,即 Eclipse 扩展点和扩展。为了在扩展点的上下文中使用 Guice,需要考虑两个方面:

提供由 Guice 注入器创建的扩展

这里解释得很好:https://code.google.com/p/peaberry/wiki/GuiceExtensionFactory。我有一点要说。扩展对象的创建是在 GuiceExtensionFactory 内部的注入器中完成的,因此它是一个自己的上下文,需要由作为工厂附加扩展的模块进行配置。如果您有其他需要自己在捆绑包中创建注入器的需求,这可能会成为一个问题。

定义一个扩展点,以便将扩展简单地注入到使用扩展的类中。

首先要做的是像往常一样定义扩展点模式文件。它应该包含必须由扩展实现的接口的引用。

扩展点的 id 必须连接到由扩展提供并由 guice/peaberry 注入的接口。因此 peaberry 提供了一个注解用于对接口进行注解:

import org.ops4j.peaberry.eclipse.ExtensionBean;

@ExtensionBean("injected.extension.point.id")
public interface InjectedInterface 
...

在某些网页上你还发现如果id等于接口的限定名,不加注解可以直接找到,但我没有尝试过。

为了启用注入,您必须做两件事来配置 Guice 注入器的创建。

首先必须将 Peaberry 的 EclipseRegistry 对象设置为 ServiceRegistry。其次,必须将扩展实现绑定到提供的服务。

注入器的创建必须以这种方式完成:

import org.osgi.framework.BundleContext;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.ops4j.peaberry.eclipse.EclipseRegistry;

import static org.ops4j.peaberry.Peaberry.*;

void initializer() 
    Injector injector = Guice.createInjector(osgiModule(context, EclipseRegistry.eclipseRegistry()), new Module() 
               binder.bind(iterable(InjectedInterface.class)).toProvider(service(InjectedInterface.class).multiple());
        );

然后可以像这样简单地注入扩展实现:

private Iterable<InjectedInterface> registeredExtensions;

@Inject
void setSolvers(final Iterable<InjectedInterface> extensions) 
    registeredExtensions = extensions;

通过所描述的方式,可以注入扩展,这些扩展由使用 Guice 的类实现以注入依赖项。

目前还没有找到使用osgi服务的解决方案,不过或许有人有想法。

最好的问候, 拉尔斯

【讨论】:

以上是关于使用 Guice/Peaberry 进行 osgi 声明式服务的主要内容,如果未能解决你的问题,请参考以下文章

使用 Hibernate 实现在 OSGI 上下文中使用 CXF 进行 Bean 验证

osgi + felix example2b编写

osgi+camel+karaf运行环境搭建

osgi + felix example3编写与使用服务的改进

Osgi 环境中的 NoClassDefFoundError

OSGi 用户管理服务用户对象