初探OSGi 之 DS 的运用

查了好些资料,从 2009 年的 opendoc 到 2012 年左右的一些零散例子,无非是用 felix 或者 eclipse 自带的插件环境来测试。于是想了想,不如就从 eclipse 入手吧。

我用的开发工具是 eclipse Neon 3 ,配合 Jdk 8 来使用。填写项目名称后,一路自动生成,选了一个 DecliaritiveService 的样板工程。出于方便测试的目的,我选的运行环境是 eclipse (3.5 or greater) 。明天继续更新~~~

退而求其次,我选择了先搞定一个 DS 的使用案例。首先新建一个插件项目,叫什么不重要。这里主要验证了 DS 构建网页应用需要导入的 package 和运行时需要配置的 OSGi 环境。经过实验、有用的 OSGi 运行时配置如下:

[bundles in import-package]
javax.servlet;version="3.1.0",
javax.servlet.http;version="3.1.0",
org.eclipse.osgi.framework.console;version="1.0.0",
org.osgi.framework;version="1.3.0",
org.osgi.service.component.annotations;version="1.2.0";resolution:=optional,
org.osgi.service.http;version="1.2.1",
org.osgi.util.tracker;version="1.3.1"

[bundles in run configuration]
javax.activation(1.1.0.v201211130549)
javax.annotation(1.2.0.v201602091430)
javax.el(2.2.0.v201303151357)
javax.inject(1.0.0.v20091030)
javax.jws(2.0.0.v201005080400)
javax.mail(1.4.0.v201005080615)
javax.persistence(2.1.0.v201304241213)
javax.servlet(3.1.0.v201410161800)
javax.servlet.jsp(2.2.0.v201112011158)
javax.wsdl(1.5.1.v201012040544)
javax.wsdl(1.6.2.v201012040545)
javax.xml(1.3.4.v201005080400)
javax.xml.rpc(1.1.0.v201209140446)
javax.xml.soap(1.2.0.v201005080501)
javax.xml.stream(1.0.1.v201004272200)
javax.xml.ws(2.1.0.v200902101523)
jaxb-api(2.2.7)
org.apache.felix.gogo.command(0.10.0.v201209301215)
org.apache.felix.gogo.runtime(0.10.0.v201209301036)
org.apache.felix.gogo.shell(0.10.0.v201209301605)
org.eclipse.equinox.console(1.1.200.v20150929-1405)
org.eclipse.equinox.ds(1.4.400.v20160226-2036)
org.eclipse.equinox.http.jetty(3.3.0.v20160324-1850)
org.eclipse.equinox.http.servlet(1.3.1.v20160808-1329)
org.eclipse.equinox.util(1.0.500.v20130404-1337)
org.eclipse.equinox.jetty.continuation(9.3.9.v20160517)
org.eclipse.equinox.jetty.http(9.3.9.v20160517)
org.eclipse.equinox.jetty.io(9.3.9.v20160517)
org.eclipse.equinox.jetty.security(9.3.9.v20160517)
org.eclipse.equinox.jetty.server(9.3.9.v20160517)
org.eclipse.equinox.jetty.servlet(9.3.9.v20160517)
org.eclipse.equinox.jetty.util(9.3.9.v20160517)
org.eclipse.equinox.jetty.webapp(9.3.9.v20160517)
org.eclipse.equinox.jetty.xml(9.3.9.v20160517)
org.eclipse.osgi(3.11.3.v20170209-1843)
org.eclipse.osgi.services(3.5.100.v20160504-1419)

比如说我们要注册一个 Servlet 或者什么别的静态资源。在不使用 Activator 的情况下,首先写一个简单的 Component 类来获取一个 org.osgi.service.http.HttpService 实例。代码如下:

package com.maple.osgi.starter;

import javax.servlet.ServletException;

import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;

/**
 * demonstrate a binding component with DS files</p>
 * that register and un-register the servlets on demand</p>
 * @author luobenyu
 *
 */
public class Component {
	
	private HttpService httpService;
	
	private String myServletUri = "/demo/test";
	
	private String myStaticPageUri = "/page";
	
	private String myWebPagesFolder = "/webpages";

	public void setHttpService(HttpService httpService) {
		this.httpService = httpService;
	}
	
	public void ungetHttpService(HttpService httpService) {
		this.httpService = null;
	}
	
	/**
	 * register servlet within DS files
	 */
	public void startup(){
		try {
			HttpContext ctx = this.httpService.createDefaultHttpContext();
			// register servlet
			this.httpService.registerServlet(this.myServletUri, new DefaultServlet(), null, ctx);
			// register static resources
			this.httpService.registerResources(this.myStaticPageUri, this.myWebPagesFolder, ctx);
		} catch (ServletException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (NamespaceException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}
	
	/**
	 * unregister servlet within DS files
	 */
	public void shutdown(){
		this.httpService.unregister(this.myServletUri);
		this.httpService.unregister(this.myWebPagesFolder);
	}
	
}

这里简单定义了 Component 启动和关闭时的动作,主要就是注册和反注册(取消注册)http 资源。接下来我们要让 osgi 认得这个 Component,右键单击 Component 类,选择"new"-> "component definition"。我会事先在项目的根目录创建一个 OSGI-INF 文件夹,component definition 的位置指向这个文件夹、同时把类指向 Component 类。生成之后还有一个问题,要注意 MANIFEST.MF 文件里面,对 的描述不可以重复、否则项目一直启动不来。贴一下用到的 DefaultServlet 类和其他文件:

package com.maple.osgi.starter;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * demonstrate a simple request
 * @author luobenyu
 *
 */
public class DefaultServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8989572162853489148L;
	
	public void doGet(HttpServletRequest request, HttpServletResponse response){
		response.setContentType("text/html");
		PrintWriter writer = null;
		try {
			writer = response.getWriter();
			writer.println("Hello Default Servlet!");
			writer.flush();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} finally {
			if (writer != null) {
				writer.close();
			}
		}
	}

}

贴一下 OSGI-INF 目录下的 component definition 文件(加什么名字都行,注意事项见 MANIFEST.MF 处):

<?xml version="1.0" encoding="UTF-8"?>
<!-- rename this file as you wish -->
<!-- DO NOT add duplicated reference in 'Service-Component' at MANIFEST.MF -->
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.maple.osgi.starter" 
activate="startup" deactivate="shutdown">
   <!-- works under 'dynamic' policy -->
   <reference name="httpService" bind="setHttpService" unbind="ungetHttpService" interface="org.osgi.service.http.HttpService" policy="dynamic" cardinality="1..1" />
   <implementation class="com.maple.osgi.starter.Component"/>
</scr:component>

这里主要是 cardinality 属性的使用,默认是 1..1 也就是必须创建、只创建一个。最后是 MANIFEST.MF:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Starter
Bundle-SymbolicName: com.maple.osgi.starter
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: MAPLE
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Service-Component: OSGI-INF/*.xml
Import-Package: javax.servlet;version="3.1.0",
 javax.servlet.http;version="3.1.0",
 org.eclipse.osgi.framework.console;version="1.0.0",
 org.osgi.framework;version="1.3.0",
 org.osgi.service.component.annotations;version="1.2.0";resolution:=optional,
 org.osgi.service.http;version="1.2.1",
 org.osgi.util.tracker;version="1.3.1"
Bundle-ActivationPolicy: lazy

这里的 Service-Component 字段告诉了 osgi 在哪里找这些 component definition,所以我用 * 通配符代表了任意文件。主要是新增或者删除后重建 component definition ,eclipse 都会自动往原来的值后面追加新文件的名字(重复了!),容易导致启动不了。然后右键 "run as"->"OSGi framework",新建一个运行时配置、用上面的依赖来跑,就不用总是启动一大堆无关的 bundle 了。

后面回顾近几年撰写的资料,许多人关心的问题应该是这些(也将继续更新):

  • 怎样把 MVC 项目(包含 Servlet 和 Spring 的扩展、web项目必需的一些配置文件)放进一个插件项目?
  • 怎样控制 Spring 或者其他使用全局 classloader 的库,顺利转换到 OSGi 插件中运行?
  • 怎样保证 Hibernate 或者 Mybatis 等查询框架的 session (插件间)同步问题?

附上参考的一些资料地址:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值