Servlets 如何从OSGiHttpService中注册的Servlet获取OSGi服务引用?

Servlets 如何从OSGiHttpService中注册的Servlet获取OSGi服务引用?,servlets,dependency-injection,osgi,service-reference,Servlets,Dependency Injection,Osgi,Service Reference,在OSGi环境中运行的HttpServlet(即在OSGi中注册的)希望调用一些OSGi服务来完成其任务,这似乎很自然。问题是如何在servlet中获取对这些OSGi服务的引用 一种方法是将依赖项注入正在注册到OSGi HttpService的HttpServlet实例,如下所示: MyServlet servlet = new MyServlet(); servlet.setFooService(fooService); httpService.registerServlet("/myser

在OSGi环境中运行的HttpServlet(即在OSGi中注册的)希望调用一些OSGi服务来完成其任务,这似乎很自然。问题是如何在servlet中获取对这些OSGi服务的引用

一种方法是将依赖项注入正在注册到OSGi HttpService的HttpServlet实例,如下所示:

MyServlet servlet = new MyServlet();
servlet.setFooService(fooService);

httpService.registerServlet("/myservlet", servlet, initparams, context);
我不确定这是否是一种有效的方法,因为在非OSGi环境中,servlet生命周期由Web容器管理,因此不会为稍后创建的servlet实例注入服务引用

当作为OSGi HttpService的实现使用时,还有另一种方法可以解决这个问题。PaxWeb将OSGiBundleContext作为一个特殊属性“OSGiBundleContext”导出到ServletContext中。BundleContext随后可用于获取必要的服务引用:

public void init(ServletConfig servletConfig) throws ServletException {

    ServletContext context = servletConfig.getServletContext()
    BundleContext bundleContext = 
        (BundleContext) context.getAttribute("osgi-bundlecontext");

    ServiceReference serviceRef =
         bundleContext.getServiceReference("com.foo.FooService")
}

然而,这种方法相当难看,它将您与OSGi HttpService的具体实现联系在一起。您知道这个问题的其他(可能更好)解决方案吗?

您可以将服务注入到某个对象中,然后由servlet查询该对象。

如果您使用setter作为服务的依赖项,如您所示,它也可以在OSGi之外工作。您只需要使用其他依赖项注入机制。如果没有,您可以提供一个子类,使用JNDI查找或从servlet上下文初始化servlet

public class MyServlet_AdapterForMissingDI extends MyServlet{

    public void init(ServletConfig config){
        setFooService(getItFromSomewhere());
    }

}
要点是,如果您有可以注入
setFooService
的DI功能,那么您可以在OSGi和其他地方使用相同的servlet,如果您没有(并且仍然希望支持这种情况),那么您可以提供一个适配器

在相关说明中,请查看Felix SCR以配置对象的依赖项,以及Pax Web Extender白板,它负责将servlet与HttpService连接起来

具体来说,如果没有SCR和白板,您需要考虑fooService稍后变得不可用,或者HttpService在servlet之后启动的情况。 在这些情况下,您的servlet将引用一个死服务,以防止捆绑包被垃圾收集,或者您的servlet将不会注册到HttpService

更新:这是我为一个servlet使用的SCR描述符。SCR处理servlet实例化、生命周期、注册(通过白板)和依赖关系。servlet中没有特定于OSGi的代码。甚至不再需要BundleActivator(SCR注册所有服务):



servlet的依赖项在
reference
标记中指定。SCR将执行服务查找和绑定

可能是一篇老帖子,你可能已经得到了答案。。 你自己是在发布felix还是其他OSGi容器。如果是这种情况,您可以将bundle上下文设置为servlet上下文的属性

public class MyServlet_AdapterForMissingDI extends MyServlet{

    public void init(ServletConfig config){
        setFooService(getItFromSomewhere());
    }

}

PAX使用http服务有什么问题。最终,线程管理和其他方面由运行此http服务的servlet容器负责。

这只是将问题转移了一个级别。如何从servlet中获取对此对象的引用?PaxWebExtender白板看起来是注册servlet的一个不错的解决方案。谢谢然而,主要的问题是如何在OSGi环境中从servlet中获取服务引用。您已经提到了JNDI查找,但感觉它不是访问OSGi服务注册表的正确方法。然后您还提到了servlet上下文,但是没有办法使用osgihttpservice接口将对象放入servlet上下文。如果我错了,请纠正我。您可以使用SCR获取OSGi内部的依赖项。关键是,您只有一个setter(如setFooService),用于注入依赖项。该setter可以从BundleActivator(如您在示例中所示)、SCR、iPojo、Spring或其他方式手动调用。这些服务负责服务跟踪,重点是servlet本身不查找其依赖项。它让塞特从某处给他们注射。您不会在OSGi内部使用JNDI。这是一个例子,说明了在没有其他DI机制的情况下,如何使同一个servlet在OSGi之外工作。只剩下一个问题:您提到SCR处理servlet生命周期(我主要指的是实例化)。在标准场景中,Servlet由Servlet容器实例化(例如,处理“implements SingleThreadModel”之类的事情)。换句话说,通常只通过提供servlet类而不是具体的servlet实例来注册servlet。可以假定OSGi HttpService的实现只使用传递给registerServlet()方法的servlet实例吗?规范对此并不完全清楚。谢谢。OSGi HttpService将只使用您传递给registerServlet()的实例。我不确定它是否对它们调用init()。