java OSGI 环境中的依赖注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11164432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 04:02:33  来源:igfitidea点击:

Dependency Injection in OSGI environments

javadependency-injectionosgiguiceapache-felix

提问by ilikeorangutans

First some background:

首先介绍一下背景:

I'm working on some webapp prototype code based on Apache Slingwhich is OSGI based and runs on Apache Felix. I'm still relatively new to OSGI even though I think I've grasped most concepts by now. However, what puzzles me is that I haven't been able to find a "full" dependency injection (DI) framework. I've successfully employed rudimentary DI using Declarative Services (DS). But my understanding is that DS are used to reference -- how do I put this? -- OSGI registered services and components together. And for that it works fine, but I personally use DI frameworks like Guiceto wire entire object graphs together and put objects on the correct scopes (think @RequestScopedor @SessionScopedfor example). However, none of the OSGI specific frameworks I've looked at, seem to support this concept.

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

I've started reading about OSGI blueprintsand iPOJObut these frameworks seem to be more concerned with wiring OSGI services together than with providing a full DI solution. I have to admit that I haven't done any samples yet, so my impression could be incorrect.

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

Being an extension to Guice, I've experimented with Peaberry, however I found documentation very hard to find, and while I got basic DI working, a lot of guice-servlet's advanced functionality (automatic injection into filters, servlets, etc) didn't work at all.

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

So, my questions are the following:

所以,我的问题如下:

  1. How do declarative services compare to "traditional" DI like Guice or Spring? Do they solve the same problem or are they geared towards different problems?
  2. All OSGI specific solutions I've seen so far lack the concept of scopes for DI. For example, Guice + guice-servlet has request scoped dependencies which makes writing web applications really clean and easy. Did I just miss that in the docs or are these concerns not covered by any of these frameworks?
  3. Are JSR 330and OSGI based DI two different worlds? iPOJO for example brings its own annotationsand Felix SCR Annotationsseem to be an entirely different world.
  4. Does anybody have experience with building OSGI based systems and DI? Maybe even some sample code on github?
  5. Does anybody use different technologies like Guice and iPOJO together or is that just a crazy idea?
  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,或者这只是一个疯狂的想法?

Sorry for the rather long question.

抱歉问了这么长的问题。

Any feedback is greatly appreciated.

非常感谢任何反馈。



Updates

更新

Scoped injection: scoped injection is a useful mechanism to have objects from a specific lifecycle automatically injected. Think for example, some of your code relies on a Hibernate session object that is created as part of a servlet filter. By marking a dependency the container will automatically rebuild the object graph. Maybe there's just different approaches to that?

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

JSR 330 vs DS: from all your excellent answers I see that these are a two different things. That poses the question, how to deal with third party libraries and frameworks that use JSR 330 annotations when used in an OSGI context? What's a good approach? Running a JSR 330 container within the Bundle?

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

I appreciate all your answers, you've been very helpful!

我感谢您的所有回答,您对我很有帮助!

采纳答案by Robert Munteanu

Overall approach

总体方法

The simplest way to have dependency injection with Apache Sling, and the one used throughout the codebase, is to use the maven-scr-plugin.

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

You can annotate your java classes and then at build time invoke the SCR plugin, either as a Maven plugin, or as an Ant task.

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

For instance, to register a servlet you could do the following:

例如,要注册一个 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    
}

Specific answers

具体答案

How do declarative services compare to "traditional" DI like Guice or Spring? Do they solve the same problem or are they geared towards different problems?

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

They solve the same problem - dependency injection. However (see below) they are also built to take into account dynamic systems where services can appear or disappear at any time.

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

All OSGI specific solutions I've seen so far lack the concept of scopes for DI. For example, Guice + guice-servlet has request scoped dependencies which makes writing web applications really clean and easy. Did I just miss that in the docs or are these concerns not covered by any of these frameworks?

到目前为止,我看到的所有 OSGI 特定解决方案都缺乏 DI 范围的概念。例如,Guice + guice-servlet 具有请求范围的依赖关系,这使得编写 Web 应用程序非常干净和容易。我是否只是在文档中遗漏了这些问题,或者这些问题是否未包含在任何这些框架中?

I haven't seen any approach in the SCR world to add session-scoped or request-scoped services. However, SCR is a generic approach, and scoping can be handled at a more specific layer.

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

Since you're using Sling I think that there will be little need for session-scoped or request-scoped bindings since Sling has builtin objects for each request which are appropriately created for the current user.

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

One good example is the JCR session. It is automatically constructed with correct privileges and it is in practice a request-scoped DAO. The same goes for the Sling resourceResolver.

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

If you find yourself needing per-user work the simplest approach is to have services which receive a JCR Sessionor a Sling ResourceResolverand use those to perform the work you need. The results will be automatically adjusted for the privileges of the current user without any extra effort.

如果您发现自己需要每个用户的工作,最简单的方法是让服务接收 JCRSession或 Sling,ResourceResolver并使用它们来执行您需要的工作。结果将根据当前用户的权限自动调整,无需任何额外工作。

Are JSR 330 and OSGI based DI two different worlds? iPOJO for example brings its own annotations and Felix SCR Annotations seem to be an entirely different world.

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

Yes, they're different. You should keep in mind that although Spring and Guice are more mainstream, OSGi services are more complex and support more use cases. In OSGi bundles ( and implicitly services ) are free come and go at any time.

是的,它们是不同的。你应该记住,虽然 Spring 和 Guice 更主流,但 OSGi 服务更复杂,支持更多用例。在 OSGi 中,bundle(和隐含的服务)是随时自由来去的。

This means that when you have a component which depends on a service which just became unavailable your component is deactivated. Or when you receive a list of components ( for instance, Servlet implementations ) and one of them is deactivated, you are notified by that. To my knowledge, neither Spring nor Guice support this as their wirings are static.

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

That's a great deal of flexibility which OSGi gives you.

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

Does anybody have experience with building OSGI based systems and DI? Maybe even some sample code on github?

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

There's a large number of samples in the Sling Samples SVN repository. You should find most of what you need there.

Sling Samples SVN 存储库中有大量示例。您应该可以在那里找到您需要的大部分内容。

Does anybody use different technologies like Guice and iPOJO together or is that just a crazy idea?

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

If you have frameworks which are configured with JSR 330 annotations it does make sense to configure them at runtime using Guice or Spring or whatever works for you. However, as Neil Bartlett has pointed out, this will not work cross-bundles.

如果您有使用 JSR 330 注释配置的框架,那么在运行时使用 Guice 或 Spring 或任何适合您的方法配置它们是有意义的。但是,正如 Neil Bartlett 指出的那样,这不适用于跨捆绑。

回答by Neil Bartlett

I'd just like to add a little more information to Robert's excellent answer, particularly with regard to JSR330 and DS.

我只想在罗伯特的出色回答中添加更多信息,特别是关于 JSR330 和 DS。

Declarative Services, Blueprint, iPOJO and the other OSGi "component models" are primarilyintended for injecting OSGi services. These are slightly harder to handle than regular dependencies because they can come and go at any time, including in response to external events (e.g. network disconnected) or user actions (e.g. bundle removed). Therefore all these component models provide an additional lifecyclelayer over pure dependency injection frameworks.

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

This is the main reason why the DS annotations are different from the JSR330 ones... the JSR330 ones don't provide enough semantics to deal with lifecycle. For example they say nothing about:

这就是 DS 注释与 JSR330 注释不同的主要原因……JSR330 注释没有提供足够的语义来处理生命周期。例如,他们只字未提:

  • Whenshould the dependency be injected?
  • What should we do when the dependency is not currently available (i.e., is it optional or mandatory)?
  • What should we do when a service we are using goes away?
  • Can we dynamically switch from one instance of a service to another?
  • etc...
  • 什么时候应该注入依赖?
  • 当依赖项当前不可用时(即它是可选的还是强制的),我们应该怎么做?
  • 当我们使用的服务消失时,我们该怎么办?
  • 我们可以从一个服务实例动态切换到另一个实例吗?
  • 等等...

Unfortunately because the component models are primarily focused on services -- that is, the linkages betweenbundles -- they are comparatively spartan with regard to wiring up dependencies insidethe bundle (although Blueprint does offer some support for this).

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

There should be no problem using an existing DI framework for wiring up dependencies inside the bundle. For example I had a customer that used Guice to wire up the internal pieces of some Declarative Services components. However I tend to question the value of doing this, because if you need DI inside your bundle it suggests that your bundle may be too big and incoherent.

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

Note that it is very important NOT to use a traditional DI framework to wire up components betweenbundles. If the DI framework needs to access a class from another bundle then that other bundle must expose its implementation details, which breaks the encapsulation that we seek in OSGi.

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

回答by Christian Schneider

I have some experience in building applications using Aries Blueprint. It has some very nice features regarding OSGi services and config admin support.

我在使用 Aries Blueprint 构建应用程序方面有一些经验。它有一些关于 OSGi 服务和配置管理支持的非常好的特性。

If you search for some great examples have a look at the code of Apache Karaf which uses blueprint for all of its wiring. See http://svn.apache.org/repos/asf/karaf/

如果您搜索一些很棒的示例,请查看 Apache Karaf 的代码,它使用蓝图进行所有接线。见http://svn.apache.org/repos/asf/karaf/

I also have some tutortials for Blueprint and Apache Karaf on my website: http://www.liquid-reality.de/display/liquid/Karaf+Tutorials

我的网站上还有一些 Blueprint 和 Apache Karaf 的教程:http: //www.liquid-reality.de/display/liquid/Karaf+Tutorials

In your environment with the embedded felix it will be a bit different as you do not have the management features of Karaf but you simply need to install the same bundles and it should work nicely.

在您的嵌入式 felix 环境中,它会有所不同,因为您没有 Karaf 的管理功能,但您只需要安装相同的捆绑包,它应该可以很好地工作。

回答by christian.vogel

I can recommend Bnd and if you use Eclipse IDE sepcially Bndtools as well. With that you can avoid describing DS in XML and use annotations instead. There is a special Referenceannotation for DI. This one has also a filter where you can reference only a special subset of services.

我可以推荐 Bnd,如果你使用 Eclipse IDE 也可以推荐 Bndtools。这样您就可以避免在 XML 中描述 DS 而是使用注释。ReferenceDI有一个特殊的注释。这个还有一个过滤器,您可以在其中仅引用一个特殊的服务子集。

回答by radmike

Running into a similar architecture problem here - as Robert mentioned above in his answer:

在这里遇到类似的架构问题 - 正如罗伯特在上面的回答中提到的:

If you find yourself needing per-user work the simplest approach is to have services which receive a JCR Session or a Sling ResourceResolver and use those to perform the work you need. The results will be automatically adjusted for the privileges of the current user without any extra effort.

如果您发现自己需要每个用户的工作,最简单的方法是让服务接收 JCR 会话或 Sling ResourceResolver 并使用它们来执行您需要的工作。结果将根据当前用户的权限自动调整,无需任何额外工作。

Extrapolating from this (and what I am currently coding), one approach would be to add @param resourceResolverto any @Servicemethods so that you can pass the appropriately request-scoped object to be used down the execution chain.

从这个(以及我目前正在编写的代码)推断,一种方法是添加@param resourceResolver到任何@Service方法,以便您可以传递适当的请求范围的对象,以便在执行链中使用。

Specifically we've got a XXXXService/ XXXXDaolayer, called from XXXXServlet/ XXXXViewHelper/ JSP equivalents. So managing all of these components via the OSGI @Serviceannotations, we can easily wire up the entire stack.

具体来说,我们已经有了一个XXXXService/XXXXDao层,从名为XXXXServlet/ XXXXViewHelper/ JSP等价物。因此,通过 OSGI@Service注释管理所有这些组件,我们可以轻松地连接整个堆栈。

The downside here is that you need to litter your interface design with ResourceResolveror Sessionsparams.

这里的缺点是你需要在你的界面设计中使用ResourceResolverSessions参数。

Originally we tried to inject ResourceResolverFactoryinto the DAO layer, so that we could easily access the session at will via the factory. However, we are interacting with the session at multiple points in the hierarchy, and multiple times per request. This resulted in session-closed exceptions.

最初我们尝试注入ResourceResolverFactory到DAO层,以便我们可以轻松地通过工厂随意访问会话。但是,我们在层次结构中的多个点与会话交互,并且每个请求多次交互。这导致会话关闭异常。

Is there a way to get at that per-request ResourceResolverreliably without having to pass it into every service method?

有没有办法ResourceResolver可靠地获取每个请求而不必将其传递给每个服务方法?

With request-scoped injection on the Service layers, you could instead just pass the ResourceResolver as a constructor arg & use an instance variable instead. Of course the downside here is you'd have to think about request-scope vs. prototype-scope service code and separate out accordingly.

使用服务层上的请求范围注入,您可以改为将 ResourceResolver 作为构造函数 arg 传递并改用实例变量。当然,这里的缺点是您必须考虑请求范围与原型范围服务代码并相应地分开。

This seems like it would be a common problem where you want to separate out concerns into service/dao code, leaving the JCR interactions in the DAO, analogous to Hibernate how can you easily get at the per-request Sessionto perform repo operataions?

这似乎是一个常见的问题,您希望将关注点分离到服务/dao 代码中,将 JCR 交互留在 DAO 中,类似于 Hibernate,您如何轻松获得每个请求Session以执行 repo 操作?

回答by Sergii Zagriichuk

I am using osgi and DI for current my project, I've choosed gemini blueprint because it is second version of SPRING DYNAMIC MODULES, Based on this information I suggest you to read Spring Dynamic Modules in Action. This book will help you to understand some parts and points how to build architecture and why is it good :)

我在当前的项目中使用 osgi 和 DI,我选择了双子座蓝图,因为它是SPRING DYNAMIC MODULES 的第二个版本,基于此信息,我建议您阅读Spring Dynamic Modules in Action。这本书将帮助你理解一些部分和要点如何构建架构以及为什么它是好的:)