打造一个Hello World OSGi Web应用程序

译文
开发 后端
本文将一步一步对OSGi Web应用开发的技巧进行讲解,包括程序注册方式和声明方式。在阅读完本文之后,相信读者便能够初步掌握OSGi Web应用的开发过程。

【51CTO精选译文】在《你好,OSGi》的之前一篇文章中,我们介绍了OSGi Web应用开发工具Equinox的配置方法,在这一篇中,我们会进行Hello World OSGi Web应用程序的开发。该练习中的应用程序是一个包含了两个资源的 OSGi 套件。***个是 helloworld.html,它是一个静态的 HTML 文件;第二个是 HelloWorldServlet,它是一个 HttpServlet。有一个重点需注意,OSGi 容器提供 HttpService 服务。每个想要处理 HTTP 请求的套件都将调用该服务上的方法来通知 OSGi 容器它能够处理哪些 URL。将 URL 注册为 OSGi 套件可处理,存在两种方式:

51CTO编辑推荐:OSGi入门与实践全攻略

程序方式:***检索来自 OSGi 的服务寄存器 HttpService,然后调用其上的方法将请求 URL 注册为套件可处理。

声明方式:在 plugin.xml 文件中定义套件可处理的请求 URL。

我们将一步一步地对这些技巧进行讲解,先从程序注册方式开始。

程序注册方式

按照下面的步骤,可使用程序方式将 URL 注册为插件可处理。

你首先应做的是参加一个新的 OSGi 插件,命名为com.javaworld.sample.osgi.web.programmatic。(有关在 Eclipse 中创建 OSGi 插件的更多信息,请查阅本系列的***节。)

打开 com.javaworld.sample.osgi.web.programmatic 的 MANIFEST.MF 文件并对其进行修改,导入 javax.servlet, javax.servlet.http, org.osgi.service.http 和org.osgi.util.tracker 包。更改完成之后,你的 MANIFEST.MF 应如列表 3 类似。

列表 3. 程序式插件的 MANIFEST.MF 文件

  1. Manifest-Version: 1.0 
  2. Bundle-ManifestVersion: 2 
  3. Bundle-Name: Webapp Plug-in  
  4. Bundle-SymbolicName: com.javaworld.sample.osgi.web.programmatic  
  5. Bundle-Version: 1.0.0 
  6. Bundle-Activator: com.javaworld.sample.osgi.web.webapp.Activator  
  7. Bundle-Vendor: JAVAWORLD  
  8. Bundle-Localization: plugin  
  9. Import-Package: javax.servlet;version="2.4.0",  
  10. javax.servlet.http;version="2.4.0",  
  11. org.osgi.framework;version="1.3.0",  
  12. org.osgi.service.http;version="1.2.0",  
  13. org.osgi.util.tracker;version="1.3.2" 
  14.  

如你所见,Import-Package 清单头的值定义了你需要导入的包列表。

在插件的根目录创建一个简单的 helloworld.html 文件,如列表 4 所示。该文件用来显示消息“Hello From helloworld.html”。

列表 4. helloworld.html

  1. < !DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
  2. < html> 
  3. < head> 
  4. < meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
  5. < title>HelloWorld OSGi Web< /title> 
  6. < /head> 
  7. < body> 
  8. < h3>Hello From helloworld.html< /h3> 
  9. < /body> 
  10. < /html> 
  11.  

下一步,创建如列表 5 所示的 HelloWorldServlet。

列表 5. HelloWorldServlet

  1. package com.javaworld.sample.osgi.web.webapp;  
  2. import java.io.IOException;  
  3. import javax.servlet.ServletException;  
  4. import javax.servlet.http.HttpServlet;  
  5. import javax.servlet.http.HttpServletRequest;  
  6. import javax.servlet.http.HttpServletResponse;  
  7. public class HelloWorldServlet extends HttpServlet{  
  8. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
  9. resp.setContentType("text/html");  
  10. resp.getWriter().println("< h3>Hello from HelloWorldServlet< /h3>");  
  11. }  
  12. }  
  13.  

HelloWorldServlet 类对 HttpServlet 进行扩展并重写其 doGet() 方法。新的 doGet() 方法唯一的操作就是在输出中写入“Hello from HelloWorldServlet”。

下一步,你需要在 com.javaworld.sample.osgi.web.programmatic 插件启动时执行相同的代码。Activator.java 将作为该插件的套件的激活器(Activator),如列表 6 所示。

列表 6. Activator.java

  1. import org.osgi.framework.BundleActivator;  
  2. import org.osgi.framework.BundleContext;  
  3. import org.osgi.util.tracker.ServiceTracker;  
  4. public class Activator implements BundleActivator {  
  5. ServiceTracker httpServiceTracker;  
  6. public void start(BundleContext context) throws Exception {  
  7. System.out.println("Hello World!!");  
  8. httpServiceTracker = new HttpServiceTracker(context);  
  9. httpServiceTracker.open();  
  10. }  
  11.  
  12. public void stop(BundleContext context) throws Exception {  
  13. System.out.println("Goodbye World!!");  
  14. httpServiceTracker.close();  
  15. httpServiceTracker = null;  
  16. }  
  17. }  
  18.  

Activator 类对 BundleActivator 进行扩展并实现了两个方法:

start():当 OSGi 容器启动该插件时调用 start() 方法。在start()HttpServiceTracker 类 的一个对象;这是你用来跟踪 HttpService 的 ServiceTracker 类。一旦你拥有了 HttpService 类的一个对象,可以调用它的 open() 方法来开始跟踪 HttpService。

stop():当关闭插件时,OSGi 容器调用 stop() 方法。在 stop() 方法内,你调用 HttpServiceTracker 对象的 close() 方法来终止跟踪 HttpService。

***一步是创建 HttpServiceTracker 类,如列表 7 所示。

列表 7. HttpServiceTracker

  1. import org.osgi.framework.BundleContext;  
  2. import org.osgi.framework.ServiceReference;  
  3. import org.osgi.service.http.HttpService;  
  4. import org.osgi.util.tracker.ServiceTracker;  
  5. public class HttpServiceTracker extends ServiceTracker{  
  6. public HttpServiceTracker(BundleContext context) {  
  7. super(context, HttpService.class.getName(), null);  
  8. }  
  9. public Object addingService(ServiceReference reference) {  
  10. HttpService httpService = (HttpService) context.getService(reference);  
  11. try {  
  12. httpService.registerResources("/helloworld.html""/helloworld.html"null);  
  13. httpService.registerServlet("/helloworld"new HelloWorldServlet(), nullnull);  
  14. catch (Exception e) {  
  15. e.printStackTrace();  
  16. }  
  17. return httpService;  
  18. }  
  19. public void removedService(ServiceReference reference, Object service) {  
  20. HttpService httpService = (HttpService) service;  
  21. httpService.unregister("/helloworld.html");  
  22. httpService.unregister("/helloworld");  
  23. super.removedService(reference, service);  
  24. }  
  25. }  
  26.  

HttpServiceTracker 介绍

HttpService 是一项 OSGi 服务,允许 OSGi 环境中的套件动态的注册以及取消注册 HttpService 的 URI 名称空间中的资源和 servlet —— 换句话说,即将请求 URI 映射到一个静态 HTML 文件或一个 HttpServlet。HttpServiceTracker 类是类型 ServiceTracker 的一个对象,后者简化了对 HttpService 的跟踪。(有关 OSGi 的 ServiceTracker 的更多信息,请查阅本系列文章的***节中的“跟踪服务”。)

列表 7 中 HttpServiceTracker 类重写了两个方法:addingService() 和 removedService()。有必要对这两个方法进行解释一下:

addingService()

一个回调方法,一旦 HttpService 可用时将对其调用。在这个方法中,首先调用 HttpService.registerResources("/helloworld.html", "/helloworld.html", null),将 helloworld.html 文件映射到 /helloworld.html。之后,每当你请求 http://localhost/helloworld.html 时, HttpService 将为用户提供 helloworld.html。请注意,你无需将 helloworld.html 映射到 /helloworld.html URL;文件名无需匹配该地址,并且你可以将其映射到类似 /test.html 的文件上。

如果想要在你的插件中提供(serve)多个 HTML 文件,你需要创建多个目录。如果想要一个 /html 目录,可以通过调用 HttpService.registerResources("/html", "/html", null) 来注册它。然后,如果你还想要访问 html 文件夹中的 test.htm,相应的地址是 http://localhost/html/test.html。registerServlet() 方法用于将 URL 映射到 HttpServlet 类。在这个简单的代码中,利用对 registerServlet("/helloworld", new HelloWorldServlet(), null, null) 的调用将 /helloworld URL 映射到 HelloWorldServlet 类。如需将初始化参数传递到你的 HttpServlet,你可以创建一个 java.util.Dictionary  对象并将其作为第三方自变量传递到 registerServlet()。

removedService()

每当重写你的 ServiceTracker 中的 addingService() 方法来获得一个服务时,还是重写 removedService() 来取消该服务。在 removedService() 方法内,你调用 unregister() 方法来取消注册  /helloworld.html 和  /helloworld URI。这将通知 HttpService :com.javaworld.sample.osgi.web.programmatic 不再想要为指定 URL 提供请求服务。如果你调用 unregister() 方法来取消对 servlet 的注册, 该 servlet 的 destroy() 方法将被调用以便对其自身进行清除。

现在,HelloWorld OSGi Web应用程序已经准备就绪,并且你可以在 Equinox OSGi 框架中执行你全部的套件。你应该能够通过 http://localhost/helloworld.html 访问 helloworld.html,以及通过 http://localhost/helloworld 访问 HelloWorld 的servlet。

声明注册方式

你可能已经注意到,通过程序方式将请求 URL 注册为 OSGi 创建可处理,相应的工作流并不小。而且,如果想要更改 helloworld.html 的 URL(比如从 /helloworld.html 更改到 /hello.html),你将不得不更新 HttpServiceTracker.java,重新编译代码,然后在 OSGi 容器中对其进行部署。下面,我们来看看声明方式,它稍微简单点。

1. 创建一个新的插件项目,com.javaworld.sample.osgi.web.declarative。选择 OSGi Equinox 框架作为目标平台。

2. 编辑 com.javaworld.sample.osgi.web.declarative 套件的 MANFIEST.MF 文件,导入 javax.servlet 和 javax.servlet.http 包并将 org.eclipse.equinox.http.registry  设置为该套件的被请求套件。完成这项修改之后,你的 MANIFEST.MF 文件将与列表 8 类似。

列表 8. 声明方式插件的 MANIFEST.MF 文件

  1. Manifest-Version: 1.0 
  2. Bundle-ManifestVersion: 2 
  3. Bundle-Name: Declarative Plug-in  
  4. Bundle-SymbolicName: com.javaworld.sample.osgi.web.declarative;singleton:=true  
  5. Bundle-Version: 1.0.0 
  6. Bundle-Vendor: JAVAWORLD  
  7. Bundle-Localization: plugin  
  8. Import-Package: javax.servlet;version="2.4.0",  
  9. javax.servlet.http;version="2.4.0" 
  10. Require-Bundle: org.eclipse.equinox.http.registry  
  11.  

这个 Require-Bundle 清单头包含一个套件符号名的列表,在对导入搜索之后并且在套件路径搜索之前,需对其进行搜索。不过,对其请求套件,只有那些标记为通过被请求套件导出的包才是可见的。

3. 从 com.javaworld.sample.osgi.web.programmatic 套件将 helloworld.html 和 HelloWorldServlet.java 复制到 com.javaworld.sample.osgi.web.declarative 套件。

4. ***,更改 com.javaworld.sample.osgi.web.declarative 套件的 plugin.xml 文件,将所有请求注册为它能够处理,如列表 9 所示。

Listing 9. plugin.xml

  1. < ?xml version="1.0" encoding="UTF-8"?> 
  2. < ?eclipse version="3.0"?> 
  3. < plugin> 
  4. < extension-point id="servlets" name="HttpService servlets" schema="schema/servlets.exsd"/> 
  5. < extension-point id="resources" name="HttpService resources" schema="schema/resources.exsd"/> 
  6. < extension-point id="httpcontexts" name="HttpService httpcontexts" schema="schema/httpcontexts.exsd"/> 
  7. < extension 
  8. id="helloServlet" 
  9. point="org.eclipse.equinox.http.registry.servlets"> 
  10. < servlet 
  11. alias="/decl/helloworld" 
  12. class="com.javaworld.sample.osgi.web.webapp.HelloWorldServlet"> 
  13. < /servlet> 
  14. < /extension> 
  15. < extension 
  16. id="helloResource" 
  17. point="org.eclipse.equinox.http.registry.resources"> 
  18. < resource 
  19. alias="/decl/helloworld.html" 
  20. base-name="/helloworld.html" 
  21. /> 
  22. < /extension> 
  23. < /plugin> 
  24.  

请注意,plugin.xml 具有两个 < extension> 元素。***个,具有 id 属性,其值为 helloServlet,表示 HelloWorldServlet类将被用于处理 /decl/helloworld 请求。通过将 point 属性的值设置为 org.eclipse.equinox.http.registry.servlets,你可以标示这是 servlet 类。第二个 < extension> 元素,具有指定值为 helloResource 的 id 属性,表示用户请求 /decl/helloworld.html 应返回 helloworld.html 给用户。

现在,使用声明方式重新创建的 HelloWorld OSGi Web应用已经准备好了,并且你可以在 Equinox OSGi框架中执行你全部的套件。你可以通过 http://localhost/decl/helloworld.html 访问 helloworld.html 以及通过 http://localhost/decl/helloworld 访问 HelloWorld servlet。在下一篇,也是本系列的***一篇文章中,将介绍如何在Eclipse外部执行OSGi 容器,敬请关注!

【编辑推荐】

  1. 你好,OSGi!OSGi入门必读系列
  2. 初探OSGi Web应用开发利器Equinox:环境设置
  3. OSGi与Spring:设置Spring DM开发环境
  4. OSGi和Spring入门:什么是Spring动态模型(Spring DM)?
  5. OSGi是什么:Java语言的动态模块系统
责任编辑:yangsai 来源: 51CTO.com
相关推荐

2011-03-10 10:45:47

Azure“Hello Worl

2009-09-16 17:15:19

OSGi Bundle

2013-10-30 22:10:28

Clouda程序

2009-10-22 11:03:20

OSGi Web应用程

2023-09-21 08:00:00

ChatGPT编程工具

2024-03-13 13:53:10

C++程序开发

2013-05-13 09:31:29

Web App开发WebApp

2022-04-27 10:51:00

PythonMLCubePodman

2011-05-11 10:58:39

iOS

2009-09-28 14:49:08

Spring DMOSGi服务

2010-07-12 10:11:27

ibmdwWeb

2011-01-20 07:16:48

Web程序员

2013-12-26 15:25:15

Android开发安装开发环境Hello World

2012-08-17 10:07:58

IBMdW

2021-02-01 17:29:19

FlutterHello World开发

2012-05-03 11:21:58

ApacheCXFJava

2010-08-13 13:05:30

Flex应用程序

2011-06-09 09:31:40

Qt 实例

2011-11-29 16:30:42

jQTouch移动web应用

2023-05-19 08:49:58

SQLAlchemy数据库
点赞
收藏

51CTO技术栈公众号