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

标签 servlets dependency-injection osgi service-reference

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

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

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

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

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

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

最佳答案

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

public class MyServlet_AdapterForMissingDI extends MyServlet{

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

}

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

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

具体来说,如果没有 SCR 和 Whiteboard,您需要考虑 fooService 稍后变得不可用或 HttpService 在您的 servlet 之后启动的情况。 在这些情况下,您的 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 将进行服务查找和绑定(bind)。

关于servlets - 如何从 OSGi HttpService 中注册的 Servlet 获取 OSGi 服务引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1002813/

相关文章:

java - Servlet中读取请求参数

java - 使用 SpringMVC 提供静态内容

java - 在指定端口注册Servlet

OSGi 到 Spring Boot

java - 来自 OSGi 包的相对路径

javascript - Java servlet 和 javascript get 请求 : multiple requests to the same servlet, 更新了游戏状态

java - 在我的 quartz 工作中注入(inject)

c# - 简易喷油器 : How to test registrations?

c# - 如何将控制反转 (IoC) 与 Azure 辅助角色结合使用

scala - 如何使用 Scala 的蛋糕模式来实现机器人腿?