我正在开发一个Osgi包中的REST API。我正在使用Jersey将服务部署到一个带有javax servlet的jetty容器中,每个类都有REST服务。
每个类都有这样的属性
Private DBInterface dbInterface;
使用setter和getter,我需要在部署服务后(在运行时)从另一个bundle中注入对象。 所以任何人都知道这样做的方法吗?
提前致谢。
PD:我想在不将服务声明为单例的情况下执行此操作,以便从另一个服务实例(实际无状态REST)中回答每个REST请求
更新:我用于部署服务的web.xml代码是:
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.classnames</param-name>
<param-value>com.mypackage.MyServiceClass</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
答案 0 :(得分:0)
首先要说的是,您应该将该对象作为OSGi服务注册到另一个bundle activator中。在这种情况下,您几乎可以从任何地方访问它。
另一个问题是:如何从另一方访问它?有许多可能性,其中一些更好,其中一些更糟糕。
一个简单但不太好的解决方案:
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是作为Blueprint实现的一部分实现的。因此,它的工作方式与蓝图XML文件中的标记相同。您可以实例化服务引用并将其打开(在跟踪打开OSGi服务之后)。您可以使用getProxyInstance方法获取一个实现必要接口(由您提供)的对象。
根据您的界面对对象进行函数调用时:
正常的函数调用是这样的:
来电者 - &gt; OSGiService.function
通过ServiceReference Proxy对象进行的函数调用如下所示:
来电者 - &gt; ServiceReference.proxyObject - &gt; 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();