首先要说的是,您应该将该对象注册到其他bundle激活器中作为OSGi服务。在这种情况下,您几乎可以在任何地方访问它。
另一个问题是:如何从另一端访问它?有很多可能性,其中一些更好,其中一些更糟糕。
一个简单的,但没有真正很好的解决方案:
Bundle bundle = FrameworkUtil.getBundle(this.getClass());
// Getting the service and using it based on the bundle
与此解决方案,为每一次请求都将获得来自OSGi服务注册表基于过滤OSGi服务,后unget它的问题函数调用是不必要的开销。
解决方案基于ServiceTracker的:
如果使用服务跟踪器,你将面对的是你必须打开它,地方关闭的问题。在构造函数中打开可能是一个解决方案,但是您不能在休息类中找到可以关闭它的位置。解决方案可以是您创建Servlet侦听器,然后打开并关闭其中的跟踪器,并将服务跟踪器放入servlet上下文属性映射中。在您的REST函数中,您可以访问servlet上下文并获取每次调用中的服务跟踪器,而不是调用tracker.getService()。该函数将返回所需的对象,如果尚未注册,则返回null。
解决方案不具备必要把OSGi相关代码到REST类:
这是你不想使用ServiceTracker的在你的REST的代码,你不希望依赖于可能性OSGi那里。在这种情况下,你可以使用我实现的一个非常简单的库:)。它可在https://github.com/everit-org/osgi-servicereference。
方法是一样的。您可以编写一个监听器: - 创建ServiceReference - 将serviceReference的getProxtInstance调用到ServletContext中 - 根据您在REST函数中提供的接口获取代理对象,并调用其中的方法。
ServiceReference是作为Blueprint实现的一部分实现的。因此它的工作方式与标签在蓝图XML文件中的工作方式相同。您可以实例化一个服务引用并将其打开(打开OSGi服务后将被跟踪)。您可以使用getProxyInstance方法获得一个实现必要接口(由您提供)的对象。
当一个函数调用是基于对象的接口上进行:
- 如果一个OSGi提供服务的函数调用将被委托给该服务
- 如果没有OSGi服务是可用的功能调用将保持到超时(简单thread.wait)。如果在超时之前有OSGi服务,则将委托函数调用。如果不是,则会引发ServiceUnavailableException。您可以通过为ServiceReference对象设置不同的超时处理程序来覆盖超时行为。
甲正常的函数调用是这样的:
呼叫者 - > OSGiService.function
经由服务引用代理对象函数调用看起来像这样:
呼叫者 - > 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();
你不想将服务声明为单例的确切原因是什么?我认为你可以注册对象到泽西岛,所以他们将作为REST服务提供。您没有机会定义工厂或用于为每个请求实例化对象的东西。另一个问题:另一个包中的对象是如何实例化的?你用什么技术或机制来实例化它?你是使用Activator还是使用特殊技术?什么是导致其他bundle实例化该对象的事件? –
是一个催化剂是的。当包含它的包被启动时,我实例化另一个对象,在对象被“配置”的激活器中,然后我需要将它注入到REST服务中。我认为有人说这个服务需要这个对象,或者每次服务被实例化时使用Jersey,jetty或其他bundle或库来注入对象。 – Koalk
为什么你想多次实例化服务?为什么如果你安装它并将每个请求的不同部分实例化为函数内部的局部变量,那么这不好吗?你如何向泽西登记你的服务?您是否在webapp web.xml中配置它,或者您使用HTTP服务以编程方式注册它?我有一种感觉,这个解决方案对你来说很简单,但在答案之前多了解一点就好了。 –