如何从 Web 应用程序使用 OSGi 服务?
Posted
技术标签:
【中文标题】如何从 Web 应用程序使用 OSGi 服务?【英文标题】:How to use an OSGi service from a web application? 【发布时间】:2011-02-02 02:49:30 【问题描述】:我正在尝试开发一个将成为 launched from a HTTP OSGi service 的 Web 应用程序,该应用程序需要使用其他 OSGi 服务 (db4o OSGi),因为我需要引用 BundleContext
。我尝试了两种不同的方法来获取 Web 应用程序中的 OSGi 上下文:
-
将
Activator
的BundleContext
存储在Web 服务可以导入和使用的类的静态字段中。
使用FrameworkUtil.getBundle(this.getClass()).getBundleContext()
(this
是MainPage
的一个实例,Web 应用程序的一个类)。
我认为第一个选项是完全错误的,但无论如何我都遇到了两个选项中的类加载器的问题。在第二个中,它引发了LinkageError
:
java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/felix/framework/ModuleImpl$ModuleClassLoader) previously initiated loading for a different type with name "com/db4o/ObjectContainer"
也尝试过 Equinox,但我遇到了类似的错误:
java.lang.LinkageError: loader constraint violation: loader (instance of org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) previously initiated loading for a different type with name "com/db4o/ObjectContainer"
引发异常的代码是:
ServiceReference reference = context.getServiceReference(Db4oService.class.getName());
Db4oService service = (Db4oService)context.getService(reference);
database = service.openFile("foo.db");
在最后一行引发了异常,database
类是ObjectContainer
,如果我将此变量的类型更改为Object
,则不会引发异常,但它作为Object
没有用:)
更新:我尝试使用其他服务而不是 db4o,它们按预期工作。也许 db4o OSGi 包在加载它自己的类时做了一些奇怪的事情,或者我没有正确使用它。如果我从非 Web 包中使用它,它也可以工作。
【问题讨论】:
【参考方案1】:为什么不在 servlet 类的构造函数中传递 BundleContext?该类可以安全地存储上下文,因为服务在捆绑停止时停止(并且 BundleContext 变得无效)。
我建议完全避免在 OSGi 中使用类加载器,因为 a) OSGi 框架执行了很多类加载器魔术来将包彼此分开,并且 b) 当 OSGi 和启用 Java 2 安全性。这很可能会降低包的可重用性。
【讨论】:
将上下文存储在静态字段中与我在第一种方法中所做的不同吗?关于玩 Classloaders,是的,我也这么认为。谢谢。 是的,基本一样,只是另一种做法。您应该只将包上下文传递给来自同一包的对象。【参考方案2】:我不能 100% 确定这会对您有所帮助,但您可以在尝试访问其他包中的类之前尝试设置线程的上下文类加载器:
Thread currentThread = Thread.currentThread ();
ClassLoader origLoader = currentThread.getContextClassLoader ();
currentThread.setContextClassLoader (Db4oService.class.getClassLoader ());
ServiceReference reference = context.getServiceReference(Db4oService.class.getName());
Db4oService service = (Db4oService)context.getService(reference);
database = service.openFile("foo.db");
currentThread.setContextClassLoader (origLoader);
看起来 OSGi 正在检测来自另一个包 (Db4oService
) 的已加载类将由此类加载器加载。
【讨论】:
我尝试了您的解决方案,但我仍然遇到同样的问题。谢谢。【参考方案3】:使用环境 felix-server 和在 jetty 上运行 web 服务,您可以轻松地在任何 web 服务中使用任何 OSGi 服务。
首先你必须在你的 web 服务中注入 ServletContext,这样你就可以通过调用 servletContext.getAttribute("osgi-bundlecontext") 来访问 OSGi-context。结果就是您的 OSGi 捆绑上下文。
请在http://blog.meyerdaniel.ch/2012/08/accessing-osgi-services-from-servlets.html上找到完整示例
【讨论】:
以上是关于如何从 Web 应用程序使用 OSGi 服务?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Apache Karaf/OSGi 构建桌面应用程序?
在嵌入式 Jetty Web 容器内运行 OSGi 容器。可能的?