使用 OSGi 将组件注入 POJO
Posted
技术标签:
【中文标题】使用 OSGi 将组件注入 POJO【英文标题】:Injecting components into a POJO using OSGi 【发布时间】:2013-05-27 04:41:32 【问题描述】:我是 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;
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 加载的服务,加载一个或一个 stub 的 SPI。 如有必要,您仍然可以手动设置服务实例。
UPDATE4
进一步澄清:此模式不适用于从一开始就设计为在 OSGi 容器中运行的应用程序,而是适用于必须在任何地方运行的低级库,即使在 OSGi 容器上也不能假设所有消费者实际上都在使用 OSGi。
【问题讨论】:
【参考方案1】:你听起来很困惑...... :-) 服务是静态工厂的替代品,所以你的工厂不应该存在。
DS 的整体理念是针对每个组件:
-
等到它的依赖得到满足
创建实例
将实例绑定到其依赖项
在实例上调用激活
将实例注册为服务
因此,每当您获得由 DS 管理的服务时,它就已经被注入(绑定)了它的依赖项。因此,只要您保持服务依赖项,就永远不需要静态工厂……服务的整个想法是您没有静态工厂,只能使用(注入的)实例。 OSGi 最好的部分之一是您很少与工厂合作。
关于不使用注释的要求的评论。 OSGi 注释只是类时间,它们不会创建运行时依赖项。我强烈建议使用它们,因为它们使服务像一个类一样轻量级,并且与 XML 相比是类型安全的。
使用注释而不使代码混乱的一个技巧是创建扩展您希望成为 OSGi 组件的实现类,并在此类上添加注释。
【讨论】:
感谢您的反馈。工厂实现背后的原因是模块应该在任何环境中运行。所以总的来说,我所有的模块都“期望”托管注入,但如果没有发生这种情况,应该回退到工厂模式。但是让工厂支持 OSGi 可能有点傻,它可以只使用 SPI :) 除非您正在改造现有的工厂,该工厂由不支持 OSGi 的模块使用? 嗯,在 OSGi 世界中,事情看起来非常简单明了:每个对象都是一个组件。因此,在非 OSGi 世界中,您需要一些 DI 引擎来进行注入。【参考方案2】:我会说你在正确的轨道上。如果方便,您可以使用静态字段。
重要的是您让其余代码处理 QuoteConsumer 的出现和消失。因此,在您的激活器中放入代码以在 QuoteConsumer 可用时执行您需要执行的操作(在某个字段中注册它,调用一些初始化代码,我不知道)并放入您需要指示的停用代码QuoteConsumer 不再可用。
【讨论】:
代码目前基本允许三种操作模式:OSGi、SPI和手动设置,无需引入新的依赖。因此,如果 OSGi 实例被删除(或从不存在),它将回退到 SPI,如果这不起作用,您有责任自己管理它。我将使用示例代码更新原始问题【参考方案3】:要访问服务,您需要声明另一个组件对它的引用:
@Reference
public void setFoo(Foo foo)
this.foo = foo;
您可能会发现Bndtools tutorial 将有助于澄清这些概念。
【讨论】:
以上是关于使用 OSGi 将组件注入 POJO的主要内容,如果未能解决你的问题,请参考以下文章
未注入 OSGI 服务 JPA PersistenceContext
如何使用 openFromComponent 将snackBarRef 注入组件