2013-08-19 24 views
0

我正在开发一个Osgi包中的REST API。我正在使用Jersey将服务部署到具有REST服务的每个类的javax servlet的jetty容器中。在部署的REST服务上注入对象

每个类都有这样

Private DBInterface dbInterface; 

随着setter和getter属性,以及我需要从另一个束注入对象一旦服务部署(在运行时)。 那么,任何人都知道一种方法来做到这一点?

在此先感谢。

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

你不想将服务声明为单例的确切原因是什么?我认为你可以注册对象到泽西岛,所以他们将作为REST服务提供。您没有机会定义工厂或用于为每个请求实例化对象的东西。另一个问题:另一个包中的对象是如何实例化的?你用什么技术或机制来实例化它?你是使用Activator还是使用特殊技术?什么是导致其他bundle实例化该对象的事件? –

+0

是一个催化剂是的。当包含它的包被启动时,我实例化另一个对象,在对象被“配置”的激活器中,然后我需要将它注入到REST服务中。我认为有人说这个服务需要这个对象,或者每次服务被实例化时使用Jersey,jetty或其他bundle或库来注入对象。 – Koalk

+0

为什么你想多次实例化服务?为什么如果你安装它并将每个请求的不同部分实例化为函数内部的局部变量,那么这不好吗?你如何向泽西登记你的服务?您是否在webapp web.xml中配置它,或者您使用HTTP服务以编程方式注册它?我有一种感觉,这个解决方案对你来说很简单,但在答案之前多了解一点就好了。 –

回答

0

首先要说的是,您应该将该对象注册到其他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(); 
+0

我们对您提出的最后一个解决方案感兴趣,但是我们很难理解该库的工作原理。您创建的Reference实例接收服务的http请求,然后等到创建服务实例或类似的东西? – Koalk

+0

更新了答案以获得更多信息。如果事情不清楚,请告诉我。我想我会链接这个stackoverflow问题作为一个例子从ServiceReference页面的自述文件。请查阅README和Reference类的javadoc以获取更多信息。 –