1

我是 OSGi 的新手,我有兴趣将我的一些 jar 改装为 OSGi 包。但是,我不想为任何 osgi 特定的库引入额外的依赖项。

因为这样的注释是不可能的,对捆绑上下文的编程调用也是不可能的。

我发现声明式服务与我的要求几乎匹配,这允许我在不影响依赖关系的情况下公开我的较低级别的捆绑包,但是在更高级别(我实际上需要使用服务)我仍然有点卡住。

我知道组件 xml 可用于声明服务的实现(我已经将其用于我的较低级别的 jar),也可用于将服务实例注入特定的 POJO。

现在我的问题是:如何访问已注入服务的 osgi 管理的 POJO?在不引入新依赖项的情况下是否有可能,或者我必须以编程方式进行?

如果是后者,有人可以指点我一些代码的方向来做到这一点,换句话说,bundleContext.getServiceReference() 的组件等效项?

更新

澄清一下,如果您阅读本教程的第五部分:http ://www.vogella.com/articles/OSGiServices/article.html

他声明了一个 component.xml 文件,该文件使用引用绑定将服务注入到 QuoteConsumer 对象中。太好了,现在我如何获得一个注入了必要服务的 QuoteConsumer 实例,我不能很好地执行“new QuoteConsumer()”,对吗?

更新2

目前我正在将 osgi 创建的实例注册为可以请求的静态变量,我认为这不是最好的方法,尤其是因为我无法将构造函数设置为私有。(后者至少会产生一个真正的单例)

基本上工厂类有:

private void activate() {
    instance = this;
}

更新3

工厂的完整示例:

public class Factory {

    private static Factory instance;

    public static Factory getInstance() {
        if (instance == null)
            instance = new Factory();
        return instance;
    }

    private MyInterface implementation;

    public void setMyInterface(MyInterface implementation) {
        this.implementation = implementation;
    }

    public void unsetMyInterface(MyInterface implementation) {
        implementation = null;
    }

    public MyInterface getMyInterface() {
        if (implementation == null) {
            ServiceLoader<MyInterface> serviceLoader = ServiceLoader.load(MyInterface.class);
            Iterator<MyInterface> iterator = serviceLoader.iterator();
            if (iterator.hasNext())
                implementation = iterator.next();
            else
                implementation = new MyInterfaceStub();
        }
        return implementation;
    }

    @SuppressWarnings("unused")
    private void activate() {
        instance = this;
    }
    @SuppressWarnings("unused")
    private void deactivate() {
        instance = null;
    }
}

然后任何客户端代码都可以执行以下操作:

Factory.getInstance().getMyInterface();

并接收 OSGi 加载的服务、SPI 加载的一个或一个存根。如有必要,您仍然可以手动设置服务实例。

更新4

进一步澄清:此模式不适用于从头开始设计为在 OSGi 容器中运行的应用程序,而是用于必须在任何地方运行的低级库,即使在 OSGi 容器上也不能假定所有消费者都是实际使用 OSGi。

4

3 回答 3

2

你听起来很困惑...... :-) 服务是静态工厂的替代品,所以你的工厂不应该存在。

DS 的整个想法是对于每个组件:

  1. 等到它的依赖得到满足
  2. 创建一个实例
  3. 将实例绑定到其依赖项
  4. 在实例上调用激活
  5. 将实例注册为服务

因此,每当您获得由 DS 管理的服务时,它就已经被注入(绑定)了它的依赖项。因此,只要您保持服务依赖关系,就永远不需要静态工厂……服务的整个想法是您没有静态工厂,只能使用(注入)实例。OSGi 最好的部分之一是您很少使用工厂。

关于不使用注释的要求的评论。OSGi 注释只是类时间,它们不会创建运行时依赖项。我强烈建议使用它们,因为它们使服务像一个类一样轻量级,并且与 XML 相比是类型安全的。

使用注释而不使代码混乱的一个技巧是创建扩展您希望成为 OSGi 组件的实现类,并在此类上添加注释。

于 2013-06-01T10:08:34.793 回答
1

要访问服务,您需要从另一个组件声明对它的引用:

@Reference
public void setFoo(Foo foo) {
    this.foo = foo;
}

您可能会发现Bndtools 教程将有助于阐明这些概念。

于 2013-05-31T13:03:47.030 回答
0

我会说你在正确的轨道上。如果方便,您可以使用静态字段。

重要的是您让其余代码处理 QuoteConsumer 的出现和消失。因此,在您的激活器中放入代码以在 QuoteConsumer 可用时执行您需要做的事情(在某个字段中注册它,调用一些初始化代码,我不知道)并放入您需要指示的停用代码QuoteConsumer 不再可用。

于 2013-05-31T13:07:50.403 回答