使用OSGi将组件注入POJO

问题描述:

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

I'm new to OSGi and I'm interested in retrofitting some of my jars as OSGi bundles. However I do not want to introduce additional dependencies to any osgi-specific libraries.

因为注释是不可能的,所以对于绑定上下文的编程调用是不可能的.

As such annotations are out of the question as are programmatic calls to bundle contexts and what not.

我发现声明式服务几乎符合我的要求,这使我可以公开我的较低级别的捆绑包而不会影响依赖关系,但是在较高级别(我实际上需要使用这些服务的地方),我仍然有些卡住.

I have found a near match to my requirements in declarative services which allows me to expose my lower level bundles without impacting dependencies however at the higher level (where i actually need to consume the services) i'm still a bit stuck.

我了解组件xml可用于声明服务的实现(我已经在较低级别的jar中使用了该实现),还可以将服务实例注入特定的POJO中.

I understand that the component xml can be used to declare implementations of services (which i already use for my lower level jars) but also to inject service instances into a specific POJO.

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

Now my question: how do I get access to the osgi-managed POJO which has the services injected into it? Is it at all possible without introducing new dependencies or do I have to do it programmatically?

如果是后者,那么有人可以指出我要执行某些代码的方向,换句话说就是bundleContext.getServiceReference()的等效组件吗?

If the latter is the case can someone point me in the direction of some code to do it, in other words the component-equivalent of bundleContext.getServiceReference()?

更新

为澄清起见,如果您采用本教程的第五部分: http://www .vogella.com/articles/OSGiServices/article.html

To clarify, if you take the fifth part of this tutorial: http://www.vogella.com/articles/OSGiServices/article.html

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

He declares a component.xml file which uses reference binding to inject a service into the object QuoteConsumer. Great, now how do I get an instance of QuoteConsumer that has the necessary services injected into it, I can't very well do "new QuoteConsumer()" right?

UPDATE2

当前,我正在将osgi创建的实例注册为可以请求的静态变量,我认为这不是最好的方法,尤其是因为我无法将构造函数设置为private. (后者至少会导致真正的单例)

Currently I am registering the instance created by osgi as a static variable which can be requested, I'm thinking this is not the best method especially because I can't set the constructor to private. (the latter would at least result in a true singleton)

基本上,Factory类具有:

Basically the Factory class has:

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;
    }
}

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

Any client code can then do:

Factory.getInstance().getMyInterface();

并接收OSGi加载的服务,SPI加载的一个或存根. 您仍然可以根据需要手动设置服务实例.

and receive the OSGi loaded service, the SPI loaded one or a stub. You can still manually set the service instance if necessary.

UPDATE4

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

To clarify further: this pattern is not meant for applications that are designed from the ground up to be run in an OSGi container but rather for low level libraries that have to run everywhere and even when on an OSGi container must not assume that all consumers are actually using OSGi.

您听起来很困惑... :-)服务代替了静态工厂,因此您的工厂不必存在.

You sound confused ... :-) A service is a replacement for static factories so your factory should not have to exist.

DS的整体思想是针对每个组件:

The whole idea of DS is that for each component:

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

因此,每当您获得由DS管理的服务时,便已经对其依赖项进行了注入(绑定).因此,只要您不依赖服务依赖项,就永远不需要静态工厂...服务的整个思想是您没有静态工厂,而只能使用(注入)实例. OSGi最好的部分之一就是您很少与工厂合作.

So whenever you get a service managed by DS it already is injected (bound) with its dependencies. So as long as you stay with service dependencies you never need static factories ... The whole idea of service is that you do NOT have static factories and can only work with (injected) instances. One of the best parts of OSGi is that you rarely work with factories.

关于不使用注释的要求的说明. OSGi批注仅用于类时间,它们不会创建运行时依赖项.我强烈建议使用它们,因为它们使服务像类一样轻量级,并且与XML相比具有类型安全性.

One remark about the requirement not to use annotations. The OSGi annotations are class time only, they do not create a runtime dependency. I strongly suggest to use them since they make services as lightweight as a class and are typesafe in contrast to XML.

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

One trick to use the annotations and not clutter your code is to create extend your implementation classes that you want to be an OSGi component and add the annotations on this class.