Osgi相关

来源:互联网 发布:凌游网络 编辑:程序博客网 时间:2024/05/18 10:58

读者将首先了解到如何在 Servlet Container 中嵌入 OSGI,并从文章提供的例子中了了解其工作原理, 并提供一个简单的示例。通过学习了解 Servlet Container 中嵌入 OSGI, 我们也可以将这种技术用到其它的已有的系统中来部署 OSGI 应用。 OSGI 在 J2EE 环境下的应用越来越广泛,目前在 Servlet 应用中使用 OSGI 有两种方式:Servlet Container in OSGI 和 OSGI in Servlet Container. 前一种:和普通的 OSGI bundle 开发差不多, 而后一种:Equinox 提供 servletBridge 来将 OSGI framework 和 Servelet Container 联系起来。

Equinox 项目

Equinox 项目包括 OSGi R4 版本规范核心框架的实现,一系列 OSGi 标准服务 Bundle 及运行基于 OSGi 的系统的一些基础构件。 用户可以直接访问该项目在 Eclipse 的网址 Equinox 获取概括性的信息。 目前,关于 Equinox 的进展大部分资料及项目进展存在于 Eclipse Wiki 上。 可以通过 equinox 官方网站得到这些相关信息。

OSGi 作为应用服务器的基础架构已经成为现实。Equinox 提供了一组基础的 Bundle, 使得使用 JSP、Servlet 和 Struts 等 J2EE 技术的 Web 应用项目可以运行于 Equinox OSGi 环境中。 同样的,Equinox 通过一组 Bundle,可以将 Equinox OSGi 应用嵌入到现有的 Web 服务器(如 Tomcat,Jetty 等)和 应用服务器(如 Websphere,Weblogic 等)中。

下面是 Equinox 在 J2EE 应用方面的几个项目:

  • org.eclipse.equinox.servletbridge (Servlet Bridge)

    该 Bundle 会启动 OSGI,使得 Equinox 可以嵌入到现有的 servlet 容器中运行,通过提供一个供 Hook 注册的功能,使 OSGI 框架可以能够处理容器接受的 HTTP 请求。

  • org.eclipse.equinox.http.servletbridge (HTTP ServletBridge)

    注册到 Servlet Bridge 中以作为 Hook,将 servlet 容器中的 HTTP 请求转发到 OSGI 的 HTTPService 来最终完成 HTTP 请求的处理。 以上两个 bundle 是将应用服务器作为 bundle 集成进入 OSGi 大环境的关键。

  • org.eclipse.equinox.http.servlet (HTTP Servlet)

    该 Bundle 为在 Equinox 中发布其他 servlet 处理引擎(如传统的应用服务器)为 OSGi HTTP 服务提供支持 。

上面三个 project 是 Equniox 提供的将 OSGI 嵌入 servlet 容器所必须的。

BridgeServlet 快速开始

在进一步分析 BridgeServlet 实现的方法之前,我们先看一个使用 BridgeServlet 的例子,已经完成的例子, 可以在附件中下载,可以直接解压缩后在 tomcat 上部署。

  1. 部署 bridge.war,这里使用 tomcat,从 equinix 网站得到 war 包后, 直接拷贝到 tomcat 应用部署目录下即可,由于 OSGI 的 shell 窗口 和 tomcat 共享一个后台界面, 后台的信息会混合在一起,按一下回车后即可得到比较清晰的 OSGI Shell 命令行窗口:
    图 1. 部署 bridge
    图片示例
  2. Equinox OSGI 状态
    图 2. 部署后 OSGI 状态
    图片示例
  3. 安装示例 bundle
    图 3. 安装示例程序
    图片示例
  4. 启动安装好的 bundle,并访问。当启动该 bundle 的时候,按照图中的提示, 可以通过 /bridge/helloworld 来访问我们的 servlet, 路径中的 bridge 是我们的应用的 web context. 在 IE 中输入相应的地址后如下图:
    图 4. 启动 bundle,并访问
    图片示例

ServletBridge 实现方法探寻

如前所述 ServletBridge 提供了一个入口,能让 OSGI(这里是 Equinox)来处理 HTTP 请求,另一方面也能够通过 Web 来对 OSGI 框架进行控制,例如对 OSGI 进行启动和停止等等。实现 ServletBridge 并不是很复杂,最关键一点就是 ClassLoader 的处理,因为 OSGI 中有一套自己的类装载机制,每个 Bundle 都是由独立的 classloader 来装载。另外需要提供一个让 HOOK 注册的功能,这样在 Servlet Container 中的 ServletBridge 就可以调用注册的 HttpServlet 来处理 HTTP 请求,而要能提供这个功能也需要有 ClassLoader 的处理。

Org.eclipse.equinox.servletbridge bundle 中仅仅有 3 个文件:BridgeServlet.java CloseableURLClassLoader.java 和 FrameworkLauncher.java BridgeServlet 在 init() 方法中对 equinox 进行了初始化和启动,在处理 HTTP 请求的 service() 方法中,调用注册进来的 HttpServlet.

在 BirdgeServlet 中 , 为了能够找到 OSGI 中的 class,做了一下几个对于 ClassLoader 的处理:

  1. 原始 context classloader 的保存
     ClassLoader original = Thread.currentThread().getContextClassLoader();
  2. 获取用来处理 http 请求的内部 Servlet
     HttpServlet servletReference = acquireDelegateReference();
  3. 设置 context classloader,并完成 HTTP 请求的处理
     Thread.currentThread().setContextClassLoader(                           framework.getFrameworkContextClassLoader());  servletReference.service(req, resp);
  4. 将 context classloader 复原
     Thread.currentThread().setContextClassLoader(original);

在上面的截图中(图 4 中),可以看到后台打印的 original 和框架的 classloader。可以看到,原始的 classloader 是 web container 的 WebappClassLoader, 而 OSGI 框架使用的 classloader 是 Contextfinder。而两个不同的 classloader 装载 class 的策略是完全不一样的,所以当要使用 OSGI 的时候,BridgeServlet 将程序的 ContextClassLoader 进行了相应的设置,使用了 OSGI 框架的类装载器,当代码的执行返回到 webcontainer 的时候又将其设回为原来的类装载器。

另外这里 acquireDelegateReference() 方法将获得 OSGI 注册进来的 Hook,并使用这个 Hook 来完成 HTTP 请求的进一步处理。完成这个注册工作的是另外的一个 bundle org.eclipse.equinox.http.servletbridge。这个 bundle 只由一个 activator 组成,这个 activator 完成的工作也很简单:

 private HttpServiceServlet httpServiceServlet;  public void start(BundleContext context) throws Exception {  httpServiceServlet = new HttpServiceServlet();  BridgeServlet.registerServletDelegate(httpServiceServlet);  }  public void stop(BundleContext context) throws Exception {  BridgeServlet.unregisterServletDelegate(httpServiceServlet);  httpServiceServlet = null;

就是将一个 HttpServiceServlet 实例注册到 BridgeServlet 中,这里要处理的一个问题是:在 OSGI 中的 activator 是如何找到 BridgeServlet 的,因为 BridgeServlet 是部署成一个 war 包的,而 BridgeServlet 并不在 OSGI 的类装载体系结构中。为了能够让 OSGI 能够使用到 BridgeServlet,在 FrameworkLauncher 中动态的部署了一个 extension bundle,这个生成的 extension bundle 可以在 tomcat 的 /work 目录下找到,在这个生成的 bundle:org.eclipse.equinox.servletbridge.extensionbundle_1.0.0.jar 里面,没有包含任何代码,只是在 manifext.mf 里面使用 Fragment-Host: system.bundle; extension:=framework 来说明这是一个“boot class path extension bundle“,并将

”org.eclipse.equinox.servletbridge; version=1.0, javax.  servlet; version=2.5, javax.servlet.http; version=2.5, javax.servlet.  resources; version=2.5 “

export 出来。也就是这些 class 将从 boot class path 上去加载。因此 OSGI 将使用 WebappClassloader 来完成 bridgeServlet 的寻找,也就能找到它了。 FrameworkLauncher 和 CloseableURLClassLoader 则对 OSGI 框架的启动进行了封装,这里不做详细的介绍。

总结

本文对 BridgeServlet 做了简单的介绍,使用一个例子来对它的使用作了进一步的讲解。并对它的实现方法做了进一步的探讨,这些探讨对于如何在已有的系统中嵌入 OSGI 是一个启发,有兴趣的读者可以做进一步的了解。

0 0
原创粉丝点击