使用OSGi将组件注入POJO

时间:2013-05-31 11:11:54

标签: java osgi

我是OSGi的新手,我有兴趣将我的一些罐子改装为OSGi捆绑包。 但是,我不想为任何特定于osgi的库引入其他依赖项。

因为这样的注释是不可能的,因为程序化调用捆绑上下文而不是。

我发现声明性服务中的要求与我的要求接近匹配,这允许我公开我的低级别捆绑而不影响依赖性但是在更高级别(我实际上需要使用服务)我仍然有点卡住。

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

现在我的问题是:如何访问osgi管理的POJO,其中注入了服务?是否可以在不引入新依赖项的情况下完成,或者我是否必须以编程方式执行此操作?

如果后者是这种情况可以有人指向我做某些代码的方向,换句话说,组件相当于bundleContext.getServiceReference()?

更新

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

他声明了一个component.xml文件,它使用引用绑定将服务注入到对象QuoteConsumer中。 好的,现在我怎么得到一个QuoteConsumer的实例,它注入了必要的服务,我不能很好地做“新的QuoteConsumer()”吧?

UPDATE2

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

基本上,Factory类具有:

private void activate() {
    instance = this;
}

UPDATE3

工厂的完整示例:

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加载一个或一个存根。 如有必要,您仍然可以手动设置服务实例。

UPDATE4

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

3 个答案:

答案 0 :(得分:2)

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

DS的全部思想是针对每个组件:

  1. 等待其依赖性得到满足
  2. 创建实例
  3. 将实例绑定到其依赖项
  4. 在实例上调用activate
  5. 将实例注册为服务
  6. 因此,无论何时获得由DS管理的服务,它都已经注入(绑定)其依赖项。因此,只要您保持服务依赖性,您就永远不需要静态工厂......服务的整体理念是您没有静态工厂,只能使用(注入)实例。 OSGi最好的部分之一就是你很少与工厂合作。

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

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

答案 1 :(得分:1)

要访问服务,请从其他组件声明对它的引用:

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

您可能会发现Bndtools tutorial有助于澄清这些概念。

答案 2 :(得分:0)

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

重要的是你让其余的代码处理QuoteConsumer出现并消失。因此,在您的激活器中放入代码,以便在QuoteConsumer可用时执行您需要执行的操作(在某些字段中注册,调用一些初始化代码,我不知道)并将您需要的代码置于停用状态,以指示QuoteConsumer已不再可用。