OSGI 环境中的依赖注入

首先是一些背景:

我正在研究一些基于Apache Sling的webapp原型代码,它是基于OSGI并在Apache Felix上运行的。我对OSGI仍然比较陌生,尽管我认为我现在已经掌握了大多数概念。但是,令我困惑的是,我无法找到一个“完整”的依赖注入(DI)框架。我已经成功地使用声明性服务(DS)使用了基本的DI。但我的理解是,DS是用来引用的——我该怎么说呢?-- OSGI将服务和组件一起注册。为此,它工作正常,但我个人使用像Guice这样的DI框架将整个对象图连接在一起,并将对象放在正确的范围内(例如,想想或)。但是,我看过的OSGI特定框架似乎都不支持这个概念。@RequestScoped@SessionScoped

我已经开始阅读有关OSGI蓝图iPOJO的信息,但这些框架似乎更关心将OSGI服务连接在一起,而不是提供完整的DI解决方案。我不得不承认,我还没有做过任何样品,所以我的印象可能不正确。

作为Guice的扩展,我尝试了Peaberry,但是我发现文档很难找到,虽然我有基本的DI工作,但许多guice-servlet的高级功能(自动注入过滤器,servlet等)根本不起作用。

因此,我的问题如下:

  1. 声明式服务与 Guice 或 Spring 等“传统”DI 相比如何?他们是解决同样的问题,还是针对不同的问题?
  2. 到目前为止,我所看到的所有OSGI特定解决方案都缺乏DI范围的概念。例如,Guice + guice-servlet具有请求范围的依赖项,这使得编写Web应用程序变得非常干净和容易。我只是在文档中错过了这一点,还是这些框架中没有涵盖这些问题?
  3. JSR 330 和基于 OSGI 的 DI 是两个不同的世界吗?例如,iPOJO带来了自己的注释,而Felix SCR注释似乎是一个完全不同的世界。
  4. 有没有人有构建基于OSGI的系统和DI的经验?甚至可能是github上的一些示例代码?
  5. 有没有人一起使用不同的技术,如Guice和iPOJO,或者这只是一个疯狂的想法?

很抱歉这个问题很长。

任何反馈都非常感谢。


更新

作用域注入:作用域注入是一种有用的机制,可以自动注入特定生命周期中的对象。例如,您的一些代码依赖于作为 servlet 过滤器的一部分创建的 Hibernate 会话对象。通过标记依赖项,容器将自动重新生成对象图。也许只是有不同的方法?

JSR 330 vs DS:从你所有优秀的答案中,我看到这是两回事。这就提出了一个问题,在OSGI上下文中使用JSR 330注释时,如何处理使用JSR 330注释的第三方库和框架?什么是好方法?在捆绑包中运行 JSR 330 容器?

我感谢你所有的回答,你一直很有帮助!


答案 1

总体方法

使用Apache Sling进行依赖注入的最简单方法,以及在整个代码库中使用的方法,是使用 maven-scr-plugin

您可以对 Java 类进行注释,然后在构建时调用 SCR 插件,将其作为 Maven 插件或 Ant 任务调用。

例如,要注册 servlet,您可以执行以下操作:

@Component // signal that it's OSGI-managed
@Service(Servlet.class) // register as a Servlet service
public class SampleServlet implements Servlet {   
   @Reference SlingRepository repository; // get a reference to the repository    
}

具体答案

声明式服务与 Guice 或 Spring 等“传统”DI 相比如何?他们是解决同样的问题,还是针对不同的问题?

他们解决了同样的问题 - 依赖注入。但是(见下文),它们也是为了考虑动态系统而构建的,在这些系统中,服务可以随时出现或消失。

到目前为止,我所看到的所有OSGI特定解决方案都缺乏DI范围的概念。例如,Guice + guice-servlet具有请求范围的依赖项,这使得编写Web应用程序变得非常干净和容易。我只是在文档中错过了这一点,还是这些框架中没有涵盖这些问题?

我还没有在SCR世界中看到任何添加会话范围或请求范围服务的方法。但是,SCR 是一种通用方法,可以在更具体的层处理范围。

由于您正在使用Sling,我认为几乎不需要会话范围或请求范围的绑定,因为Sling为每个请求都内置了对象,这些对象是为当前用户适当创建的。

一个很好的例子是JCR会话。它是使用正确的权限自动构造的,实际上它是请求范围的DAO。Sling资源解析器也是如此。

如果您发现自己需要每用户工作,最简单的方法是拥有接收JCR或Sling的服务,并使用这些服务来执行您需要的工作。结果将根据当前用户的权限自动调整,而无需任何额外的努力。SessionResourceResolver

JSR 330 和基于 OSGI 的 DI 是两个不同的世界吗?例如,iPOJO带来了自己的注释,而Felix SCR注释似乎是一个完全不同的世界。

是的,他们是不同的。您应该记住,尽管Spring和Guice更主流,但OSGi服务更复杂,并且支持更多的用例。在OSGi中,捆绑包(隐式服务)在任何时候都是免费的来来去去。

这意味着,当您的组件依赖于刚刚变得不可用的服务时,您的组件将被停用。或者,当您收到组件列表(例如,Servlet 实现 )并且其中一个组件被停用时,您将收到通知。据我所知,Spring和Guice都不支持这一点,因为它们的布线是静态的。

这是OSGi给你的很大的灵活性。

有没有人有构建基于OSGI的系统和DI的经验?甚至可能是github上的一些示例代码?

Sling Samples SVN存储库中有大量的样本。你应该在那里找到你需要的大部分东西。

有没有人一起使用不同的技术,如Guice和iPOJO,或者这只是一个疯狂的想法?

如果你有配置了JSR 330注释的框架,那么在运行时使用Guice或Spring或任何适合您的东西来配置它们确实是有意义的。然而,正如尼尔·巴特利特(Neil Bartlett)所指出的那样,这不会在交叉捆绑中起作用。


答案 2

我只想为Robert的出色答案添加更多信息,特别是关于JSR330和DS。

Declarative Services,Blueprint,iPOJO和其他OSGi“组件模型”主要用于注入OSGi服务。这些比常规依赖项稍微难以处理,因为它们可以随时来来去去,包括响应外部事件(例如网络断开连接)或用户操作(例如,删除捆绑包)。因此,所有这些组件模型都为纯依赖注入框架提供了额外的生命周期层。

这是DS注释与JSR330注释不同的主要原因...JSR330没有提供足够的语义来处理生命周期。例如,他们什么也没说:

  • 何时应注入依赖关系?
  • 当依赖项当前不可用时,我们该怎么办(即,它是可选的还是强制性的)?
  • 当我们使用的服务消失时,我们该怎么办?
  • 我们可以从服务的一个实例动态切换到另一个实例吗?
  • 等。。。

不幸的是,由于组件模型主要关注服务(即捆绑包之间的链接),因此它们在捆绑包内的连接依赖项方面相对简单(尽管蓝图确实为此提供了一些支持)。

使用现有的 DI 框架来连接捆绑包内的依赖项应该没有问题。例如,我有一个客户使用 Guice 连接一些声明性服务组件的内部部分。然而,我倾向于质疑这样做的价值,因为如果你的捆绑包中需要DI,这表明你的捆绑包可能太大且不连贯。

请注意,不要使用传统的 DI 框架在捆绑包之间连接组件,这一点非常重要。如果 DI 框架需要从另一个捆绑包访问一个类,那么另一个捆绑包必须公开其实现细节,这会破坏我们在 OSGi 中寻求的封装。


推荐