4

在 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 的具体实现联系在一起。你知道这个问题的任何其他(可能更好的)解决方案吗?

4

3 回答 3

2

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

public class MyServlet_AdapterForMissingDI extends MyServlet{

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

}

关键是如果你有可以注入的 DI 能力setFooService,你可以在 OSGi 和其他地方使用相同的 servlet,如果你不这样做(并且仍然想支持这种情况),你提供一个适配器。

在相关说明中,请查看 Felix SCR 来配置对象的依赖项,以及 Pax Web Extender Whiteboard,它负责将 servlet 与 HttpService 挂钩。

具体来说,在没有 SCR 和 Whiteboard 的情况下,您需要考虑 fooService 稍后变得不可用,或者 HttpService 在您的 servlet 之后启动的情况。在这些情况下,您的 servlet 将引用一个死服务,以防止捆绑包被垃圾收集,或者您的 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 将进行服务查找和绑定。

于 2009-06-17T07:50:58.893 回答
2

可能是一篇旧文章,您可能已经得到了答案。您是在启动 felix 还是自己启动任何 OSGi 容器。如果是这种情况,您可以将捆绑上下文设置为 servlet 上下文的属性。

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

于 2011-03-02T11:29:59.927 回答
-1

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

于 2009-06-16T19:14:07.547 回答