OSGI环境中的依赖注入

ili*_*ans 36 java osgi dependency-injection guice apache-felix

首先是一些背景:

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

我开始阅读有关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 Annotations似乎是一个完全不同的世界.
  4. 有没有人有建立基于OSGI的系统和DI的经验?甚至可能在github上有一些示例代码?
  5. 有没有人像Guice和iPOJO一样使用不同的技术,还是只是一个疯狂的想法?

抱歉这个相当长的问题.

任何反馈都非常感谢.


更新

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

JSR 330 vs DS:从你所有出色的答案中我看到这些是两个不同的东西.这提出了一个问题,如何处理在OSGI上下文中使用时使用JSR 330注释的第三方库和框架?什么是好方法?在Bundle中运行JSR 330容器?

我感谢您的所有答案,您一直非常乐于助人!

Rob*_*anu 28

总体方法

使用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    
}
Run Code Online (Sandbox Code Playgroud)

具体答案

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

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

到目前为止,我见过的所有OSGI特定解决方案都缺乏DI的范围概念.例如,Guice + guice-servlet具有请求范围依赖性,这使得编写Web应用程序非常简洁.我是否只是错过了文档中的内容,或者这些框架中没有涵盖这些问题?

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

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

一个很好的例子是JCR会话.它是使用正确的权限自动构建的,实际上是一个请求范围的DAO.Sling resourceResolver也是如此.

如果您发现自己需要按用户工作,最简单的方法是获得接收JCR Session或Sling的服务,ResourceResolver并使用这些服务来执行您需要的工作.结果将自动调整为当前用户的权限,无需任何额外的努力.

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

是的,他们是不同的.您应该记住,尽管Spring和Guice更为主流,但OSGi服务更复杂并且支持更多用例.在OSGi中,捆绑包(以及隐式服务)随时可以自由出入.

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

这是OSGi为您提供的极大灵活性.

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

Sling Samples SVN存储库中有大量样本.你应该找到你需要的大部分内容.

有没有人像Guice和iPOJO一样使用不同的技术,还是只是一个疯狂的想法?

如果你有使用JSR 330注释配置的框架,那么在运行时使用Guice或Spring或任何适合你的方法配置它们是有意义的.然而,正如尼尔巴特利特所指出的那样,这不会起到跨包的作用.


Nei*_*ett 14

我想为Robert的优秀答案添加更多信息,特别是关于JSR330和DS.

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

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

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

不幸的是,因为组件模型主要关注服务 - 即捆绑之间的联系- 它们捆绑捆绑内部的依赖关系方面相对简单(尽管Blueprint确实为此提供了一些支持).

使用现有的DI框架来连接bundle中的依赖关系应该没有问题.例如,我有一个客户使用Guice来连接一些Declarative Services组件的内部部分.但是我倾向于质疑这样做的价值,因为如果你需要在你的捆绑中使用DI,那么它表明你的捆绑包可能太大而且不连贯.

请注意,不要使用传统的DI框架 bundle 之间连接组件是非常重要的.如果DI框架需要从另一个bundle访问一个类,那么另一个bundle必须暴露其实现细节,这打破了我们在OSGi中寻求的封装.