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

时间:2009-06-16 17:13:20

标签: servlets dependency-injection osgi service-reference

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

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

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

httpService.registerServlet("/myservlet", servlet, initparams, context);

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

当使用PAX Web作为OSGi HttpService的实现时,还有另一种方法可以解决这个问题。 PAX Web将OSGi BundleContext作为特殊属性“osgi-bundlecontext”导出到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的具体实现联系起来。你知道其他(也可能是更好的)解决这个问题的方法吗?

3 个答案:

答案 0 :(得分:2)

如果您使用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 Whiteboard,它负责使用HttpService挂接您的servlet。

具体来说,如果没有SCR和Whiteboard,您需要考虑以后fooService不可用时的情况,或者在servlet之后启动HttpService。 在这些情况下,您的servlet将引用一个死服务,该服务可防止bundle被垃圾收集,或者您的servlet不会在HttpService中注册。

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

<component name="oracle.statusServlet" >
<implementation class="mypackage.DataSourceStatusServlet"/>
<property name="service.description" value="Oracle DataSource status servlet" />
<property name="alias" value="/OracleDataSourceStatus" />
<property name="servlet-name" value="Oracle DataSource status servlet" />
<service>
    <provide interface="javax.servlet.Servlet" />
</service>
    <reference name="DATASOURCES" 
            interface="javax.sql.DataSource"
            cardinality="0..n" policy="dynamic" 
            bind="bindDataSource" unbind="unbindDataSource"/>

</component>

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:-1)

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