首先要说的是,您应该在另一个捆绑激活器中将该对象注册为 OSGi 服务。在这种情况下,您几乎可以从任何地方访问它。
另一个问题是:如何从另一端访问它?有很多可能性,有些更好,有些更糟。
一个简单但不是很好的解决方案:
Bundle bundle = FrameworkUtil.getBundle(this.getClass());
// Getting the service and using it based on the bundle
这个解决方案的问题是,对于每个请求,您都必须根据过滤器从 OSGi 服务注册表获取 OSGi 服务,并在函数调用后取消获取它,这是不必要的开销。
基于ServiceTracker的解决方案:
如果您使用服务跟踪器,您将面临必须在某处打开并关闭它的问题。在构造函数中打开可能是一个解决方案,但是您不会在休息类中找到可以关闭它的位置。一个解决方案是您创建一个 Servlet 侦听器,在那里打开和关闭跟踪器,并将服务跟踪器放入 servlet 上下文属性映射中。在您的 REST 函数中,您可以访问 servlet 上下文并在每次调用中获取服务跟踪器,而不是调用 tracker.getService()。该函数将返回您需要的对象,如果尚未注册,则返回 null。
无需将 OSGi 相关代码放入 REST 类的解决方案:
您可能不想在 REST 代码中使用 ServiceTracker,因为您不想在那里依赖 OSGi。在这种情况下,您可以使用我实现的一个非常简单的库:)。它可在https://github.com/everit-org/osgi-servicereference获得。
方法论是一样的。您编写了一个侦听器: - 创建一个 ServiceReference - 您将 serviceReference 的 getProxtInstance 调用到 ServletContext - 您根据您在 REST 函数中提供的接口获取代理对象并调用其上的方法。
ServiceReference 是作为蓝图实现的一部分实现的。因此,它的工作方式与标记在蓝图 XML 文件中的工作方式相同。您可以实例化一个服务引用并打开它(打开后将跟踪 OSGi 服务)。您可以使用 getProxyInstance 方法获得一个实现必要接口(由您提供)的对象。
当基于您的接口对对象进行函数调用时:
- 如果 OSGi 服务可用,则函数调用将委托给该服务
- 如果没有可用的 OSGi 服务,则函数调用将一直保持到超时(简单的 thread.wait)。如果在超时之前存在 OSGi 服务,则将委托函数调用。如果没有,将抛出 ServiceUnavailableException。您可以通过为 ServiceReference 对象设置不同的超时处理程序来覆盖超时行为。
一个普通的函数调用是这样的:
调用者-> OSGiService.function
通过 ServiceReference 代理对象的函数调用如下所示:
调用者 -> ServiceReference.proxyObject -> OSGiService.function(如果 OSGiService 可用)
现在实践中的解决方案:
您应该为 Web 应用程序编写一个侦听器:
private Reference reference;
@Override
public void contextInitialized(final ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
BundleContext bundleContext = (BundleContext) servletContext.getAttribute("osgi-bundlecontext");
try {
Filter filter = bundleContext.createFilter("(objectClass=" + MyInterface.class.getName() + ")");
// MyInterface is the interface the OSGi service implements (there can be multiple) and the timeout until function calls will wait is 5s.
reference = new Reference(bundleContext, new Class<?>[] { MyInterface.class }, filter, 5000);
// Opening the reference is necessary to track services
reference.open();
// Taking the proxy object into the servlet context attributes
servletContext.setAttribute("myService", reference.getProxyInstance());
} catch (InvalidSyntaxException e) {
LOGGER.error(e.getMessage(), e);
}
}
@Override
public void contextDestroyed(final ServletContextEvent sce) {
if (reference != null) {
reference.close();
sce.getServletContext().removeAttribute("myService");
}
}
拥有此侦听器后,您可以在代码中的任何位置(您可以访问 servlet 上下文)中的任何地方获取如下代理对象:
MyInterface myService = servletContext.getAttribute("myService");
myService.foo();