OSGi尝试

最好的入门材料:

OSGI 实战 ,真的要感谢BlueDavy


这里还有用Webex产品录制的OSGi 的简单培训 OSGiInAction


当前的开源社区对OSGi 支持的基本情况是:

1. OSGi

 R4 core framework specification


2. Equinox latest Release3.2.2

 
3. Spring-OSGi



 1.0 M2
4. The Felix 0.8.0-incubator

 release is now available in Apache.
5. Knopflerfish 2.0.1

 released

OSGi 的特别适用于对于热插拨有强烈需求的系统,同时适合经常有系统模块的增加和删除的系统。如果你的系统没有上面的两种需求的一种,建议当前不要用OSGi 。当然这个不是定论,只是我的个人研究结果,原因如下:

 

[ 编辑 ]

1. OSGi 还没有成熟到象Spring那样,出现问题后,社区支持没有Spring那么多。

[ 编辑 ]

2. OSGi 因为要做到热插拨,所以采用了每个Bundle用自己的ClassLoader

在其Spec中有专门的章节讲述其ClassLoader的实现原理。但是当涉及到ClassLoader,我们必须面对一些我们不愿看到的事实, 实际上Java中ClassLoader的策略和管理上比较混乱。导致当前Java开源很多的Framwork和lib都有自己的 ClassLoader。如果我们的系统不用Spring,Log4J之类的框架,全部是自己的代码的话,是没有太多的问题。可以当你要引用第三方的库之 后,就要面对因为ClassLoader不同,而资源不能共享的问题。 Apache Commons Logging的Thread classloader的本来的目的是想在不同的线程能用不同的log4j配置文件,但是把Apache Commons Logging 引入OSGi 中就出现了问题,所以才有网上热烈讨论的SLF4j的解决方案。

仅管Spring-OSGi 已经提出了针对ClassLoader问题的解决方案,但是并没有纳入到OSGi 的标准中。就当前形势看OSGi 更倾向于实现自己的一套Bundles的解决方案,包括log, IoC,http, servlet。至今还没有考虑怎么兼容其它已经存在的类库的问题。

[ 编辑 ]

3. OSGi R4的Declare Service还不够强

OSGi R4的提出了一个Declare Service的Bundle,类似于Spring IoC的机制,目的是为了减少OSGi 的 侵入性,因为在R3时,用户必须用代码的方式注册Service和引用Service。 R4只要编写一个component的xml文件将现有的类声明为Service。而且不需要强制性实现接口,这是一个很好的趋势。只是还没有做到更好。 因为没有做到象Spring IoC那么强大,DS所支持的properites只是基本类型,还不能象spring那样直接注入bean。 <property name=”domain” ref=”domainBean”/>。不过希望总是有的,Spring-OSGi 的提出就是为了解决这些问题的。只是一个正式项目用Spring-OSGi 的M2版,似乎有些不可控的风险。这些项目都在发展...

[ 编辑 ]

4. Eclipse对OSGi 的开发还有些小问题

Eclipse本身尽管是用OSGi 作核心的,但是对OSGi 的开发的支持还是有一些小问题的。比如对封闭 jar包 的bundle,在IDE的工程中其它的bundle就不能识别。只能将jar包 解开为classes,然后再放到bundle中才行。

问题虽小,便是却很烦人。

但是上面的问题现在都已经有一定的解决方案,而且OSGi 在发展中,所以在OSGi R5中可能都会得到很好解决

[ 编辑 ]

下面和大家分享一下尝试的成功心得和失败经验:

因为当时是想在正式项目中应用OSGi ,所以不是写几个Test的那种尝试,愿能给大家一点帮助

[ 编辑 ]

1. 环境准备

我选择的环境比较大众化。

Eclipse3.3M6(使用最新的,是想看看对OSGi 的支持有没有更好一点,其实用Eclipse3.2.2也是一样的), Equinox OSGi R4

[ 编辑 ]

2. 最好的入门资料

OSGI 实战 ,真的要感谢BlueDavy

[ 编辑 ]

3. 了解Eclipse的OSGi 的开发环境

1) 先建立自己的我们的OSGi 运行环境。建立根目录,且定为D:\osgi \ 建立如下图的目录和文件。startup.jar是从Eclipse安装目录copy过来的。其实这个目录结构和Eclipse的安装目录结构是一样的。

Image001.png

Backup.bat是在windows下的启动脚本,其内容是: java -jar startup.jar –console

然后在Eclipse安装目录plugin子目录中copy下列OSGi 运行的基本jar包 到D:\osgi \plugins

org.eclipse.osgi _3.2.2.R32x_v20070118.jar

org.eclipse.osgi .services_3.1.100.v20060601.jar

再到http://download.eclipse.org/eclipse/equinox/drops/R-3.2.2-200702121330/index.php

去下载declare service bundle实现以及log实现。

org.eclipse.equinox.log_1.0.1.R32x_v20060717.jar

org.eclipse.equinox.ds_1.0.0.v20060601a.jar

同样copy到D:\osgi \plugins

接下来我们来配置文件。

配置文件为D:\osgi \configuration\config.ini

将其内容写为

#Configuration File
#Mon Apr 23 09:17:19 CST 2007
osgi

.clean=true
osgi

.console=
osgi

.noShutdown=true
osgi

.bundles=org.eclipse.osgi

.services_3.1.100.v20060601.jar@start, \
 org.eclipse.equinox.ds_1.0.0.v20060601a.jar@start, \
 org.eclipse.equinox.log_1.0.1.R32x_v20060717.jar @start
osgi

.bundles.defaultStartLevel=4
osgi

.framework=plugins/org.eclipse.osgi

_3.2.2.R32x_v20070118.jar
osgi

.configuration.cascaded=false
eclipse.ignoreApp=true
eof=eof

针对这个配置文件需要说明几点:

1. 每个key的含义网上已经有资料说明
2. osgi

.bundles中声明多个jar的时候,如果需要换行要加 “\”。这个网上一些资料没有说明,害我折腾了老半天。
3. osgi

.console,一般情况下空着,表示启动后就进入console模式。
如果填入一个prot号,表示是telnet的port。这个时候OSGi

进入telnet服务模式,用户可以用telnet来进行访问。
网上有人说用Equinox不能进入后台模式,而改用了Knopflerfish,
可能是不知道这种配置的作用吧,我已经在Linux下做过测试,用nohup ./backup.sh &


可以正常运行。
4. 还有一点就是对orgi.bundles配置时,bundle的声明顺序要注意。在同一级别的起动情况下,
请将越基础的bundle越声明在前面。因为我们不可能将启动顺序完全依赖于startLevel。

OK,运行backup.bat你应该会进入OSGi 的控制台。我们的自己的OSGi 环境已经搭建好了。

2) 将OSGi 运行目录配置到Eclipse中 Eclipse默认的OSGi 工作目录是Eclipse安装目录,所以我们需要配置Eclipse使其指向我们自己的OSGi 目录(D:\osgi \) 菜单Window/Preferences

Image005.png

Eclipse会自动将D:\osgi \plugins下的bundles都加载过来。下次在plugins下的jar有增减的话,打开该页面按Relod即可。

3) 建立一个OSGi Project 不建议用Eclipse的向导来建立Project,我们的工程路径一般是cvs或是svn目录,而不是eclipse workspace。所以我摸索出的建立工程的方法如下:先用向导建一个空的bundle工程

Image007.png

Image009.png

Image011.png

将这个在Eclipse workspace目录下建立的工程目录copy到你工程目录下,以后作为模板目录。

且定我们的工程目录如下

D:\cvs\myproject\
              \bundles\
                     \bundle_proejct_template\build.properties
                                         \src\
                                         \test\
                                         \bin\
                                         \META-INF\MANIFEST.MF
                                         \OSGI

-INF\

下次我们建立自己的项目时,第一步先copy一份bundle_proejct_template目录,

(如果有CVS目录,请将所有CVS目录清除),再将目录更名为你project的name

比如我们建了一个bundle工程起名为famework,

D:\cvs\myproject\bundles\framework\

Image013.png

Image015.png

Image017.png


这样一个Bundle工程就建立好了如果Eclipse没有将工程自动识别为OSGi bundle工程的话,可以在Eclipse package Explorer 中右键后如下图。

Image019.png

4) 我们的项目经常会用到log包,可是Apache common logging的ClassLoader机制和OSGi 的不兼容,所以在正式项目之前,我们必须解决这个难题。我用的网上是SLF4j的解决方案。在解决之前我们必须了解一些背景,首先我们打Log,经常会用到两个jar包 , 一个是commons-loggin包,另一个是log4j包。本质上我们是可以直接用log4j包来打log的,但是为了做到兼容其它的log,比如 Jdklog,simple log等等。其实个人觉得这个在具体的一个项目内都没什么大的意义。可是一个类库,比如spring,他就不能定死为log4j。所以spring内部的 logger都是用的commons-logging的LogFactory.getLog()。来作为log的接口,而没有直接用log4j。我们可以 在设置java环境变量 “org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger” 来指定commons logging 的实现为log4j. 而SLF4j呢,又更高一层地兼容commons logging(也是就JCL),同时兼容log4j,并且没有ClassLoader问题。

5) 建立slf4j-osgi bundle project 我们没有必要写代码,只是简单地将slf4j的jar包 做一层bundle的封装,再重新打包成jar包 ,并且作为bundle发布。先按上面介绍的方法建立slf4j-osgi bundle proejct 再download slf4j,将 slf4j-api-1.3.1.jar jcl104-over-slf4j-1.3.1.jar log4j-1.2.14.jar slf4j-log4j12-1.3.1.jar copy到 D:\cvs\myproject\bundles\slf4j-osgi \lib\ 下

D:\cvs\myproject\bundles\slf4j-osgi \META-INF\ MANIFEST.MF文件内容如下

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: slflog4josgi
Bundle-SymbolicName: slf.commons.logging.osgi


Bundle-Version: 1.1.0
Bundle-Vendor: slf
Bundle-Localization: plugin
Bundle-ClassPath: bin/, lib/jcl104-over-slf4j-1.3.1.jar, lib/slf4j-api-1.3.1.jar, lib/log4j-1.2.14.jar, lib/slf4j-log4j12-1.3.1.jar
Export-Package: org.apache.commons.logging, org.apache.log4j, org.apache.log4j.spi, org.apache.log4j.xml, org.slf4j
Import-Package: org.osgi

.framework;version="1.3.0"

D:\cvs\myproject\bundles\slf4j-osgi \build.properites文件内容如下

source.. = src/
bin.includes = bin/,\
               META-INF/,\
               lib/jcl104-over-slf4j-1.3.1.jar,\
               lib/slf4j-api-1.3.1.jar,\
               lib/log4j-1.2.14.jar,\
               lib/slf4j-log4j12-1.3.1.jar

6) 将OSGi bundle工程导出为jar包 在Eclipse Project Exploer工作区,右键选择”Export…”

Image021.png

Image023.png

Image025.png

7) 建立一个new bundle project,以测试slf4j-osgi ,为了使这个例子有一定的意义,

我们让这个bundle可以为控制台输出一个简单命令hello。

工程目录且为

D:\cvs\myproject\bundles\test-slf4j\

 
package

 gsb.service

.console

;
 
import org.eclipse.osgi

.framework.console.CommandInterpreter;


import org.eclipse.osgi

.framework.console.CommandProvider;


 
import org.apache.commons.logging.Log;


import org.apache.commons.logging.LogFactory;


 
public

 class

 SitesProviderConsole implements

 CommandProvider {


 private

 Log logger = LogFactory.getLog

(

CommandProvider.class

)

;
 public

 String

 getHelp(

)

 {


  StringBuffer

 buffer = new

 StringBuffer

(

)

;
  buffer.append

(

"\t

 sayHello – Just a test\n

"

)

;
  return

 buffer.toString

(

)

;
 }


 
 public

 void

 _sayHello(

CommandInterpreter ci)

 throws

 Exception

 {


  logger.warn

(

"logger.class="

+logger.getClass

(

)

.getName

(

)

)

;
        logger.warn

(

"This is a debug log from commons log!"

)

;
  System

.out

.println

(

"Hello, world!"

)

;
 }


}


 

META-INF/MANIFEST.MF

…
Service-Component: OSGI

-INF/console.xml
…

Import-Package: org.apache.log4j, org.apache.commons.logging, …
…

OSGI -INF/console.xml

 


<?xml

 version

="1.0"

 encoding

="UTF-8"

?>




<component

 name

="SiteProviderConsoleActivator"

>




 <implementation

 class

="gsb.service.console.SitesProviderConsole"

/>




 <service>






  <provide

 interface

="org.eclipse.

osgi

.fram

ework.console.CommandProvider"

/>




 </service>






</component>





猜你喜欢

转载自marsvaadin.iteye.com/blog/1240917
今日推荐