OSGi起步(3):bundle之间的依赖

-----------------------

原文出处:http://www.eclipsezone.com/eclipse/forums/t90544.html

原作者:Neil Bartlett 

----------------------

OSGi起步(3)bundle之间的依赖

 

在之前的教程中,我们知道bundle怎么启动和停止,以及它们如何与框架、以及相互间的生命周期进行交互。但是,bundle到底是什么呢?

 

bundle是模块。它使得我们可以把一个完整的项目分解成便于管理的模块。这些模块可以单独地加载入OSGi运行环境。问题是,不管我们是否愿意,模块间几乎总是存在依赖关系。过去简单的jar文件中,不存在一个可靠的方法来详细指明不同jar之间的依赖。(注意,manifest文件中的Class-Path属性并不是一个可靠的方法)。所以,我们永远无法保证,在运行期,某个jar中的代码是可以正常工作,还是会抛出一个ClassNotFoundException

 

OSGi很巧妙地解决了这个问题。不过,与其直接告诉你是怎么回事,我们还是做个例子来展示一下吧。好,我们直接进入代码部分。不幸的是,由于我们之前一直在使用默认的package,而这样是没法用于展示的,所以我们将从一个合适的package入手。所以,我们先写一些简单的JavaBean风格的代码。复制以下代码到osgitut/movies/Movie.java:

package  osgitut.movies;
 

public   class  Movie  {

    
private final String title;

    
private final String director;

 

    
public Movie(String title, String director) {

        
this.title = title; this.director = director;

    }


    
public String getTitle() return title; }

    
public String getDirector() return director; }

}


 

现在,我们在同一个package中创建一个接口。创建文件 osgitut/movies/MovieFinder.java,复制以下内容:

package  osgitut.movies;

 

public   interface  MovieFinder  {

    Movie[] findAll();

}


 

接下来,我们把这两个文件做成一个bundle。是的,这个bundle出奇的小,并且几乎没有任何用途,不过在本例子中已经足够用了。跟以前一样,我们需要创建一个manifest文件。创建文件MoviesInterface.mf,复制以下内容:

Manifest-Version:  1.0

Bundle-ManifestVersion: 
2

Bundle-Name: Movies Interface

Bundle-SymbolicName: MoviesInterface

Bundle-Version: 
1.0.0

Export-Package: osgitut.movies
; version="1.0.0"

 


这里有一行我们之前没有遇到过的内容: Export-Package 。这一行表示这个 bundle 将导出一个 package osgitut.movies 。在刚开始的时候,这看起来也许有些怪异,因为在旧的 jar 包中,所有的内容都是自动导出的。但是,难道你就从来没想要在一个 package 中放一些只在 jar 中可见的代码么?当然,你可以写一些 private 或者 protected 的类,但是,这样一样,它们对于 jar 中的其他 package 也是不可见的了。所以, OSGi 引入了一个很有效的代码保护层:如果一个 package 没有被 Export-Package 明确导出,那么它们就只能在你的模块中被使用。

 

也许你还注意到了,我们给这个package添加了一个版本号。我们将在后边看到它的重要性。版本号并不是必须的,但是,如果没有,那么,OSGi将自动为你的package添加版本号”0.0.0”。提供明确的版本号是一个比较好的习惯。

 

现在,我们来创建这个bundle

javac osgitut / movies / Movie . java osgitut / movies / MovieFinder . java

jar -cfm MoviesInterface
. jar MoviesInterface . mf osgitut / movies / * . class

 

我们稍后再安装这个bundle。在这之前,我们再创建一个bundle,它将依赖于之前的bundle。我们将创建一个MovieFinder接口的具体实现。复制以下内容到文件 osgitut/movies/impl/BasicMovieFinderImpl.java

package  osgitut.movies.impl;
 
import  osgitut.movies. * ;
 
public   class  BasicMovieFinderImpl  implements  MovieFinder  {

  
private static final Movie[] MOVIES = new Movie[] {

    
new Movie("The Godfather""Francis Ford Coppola"),

    
new Movie("Spirited Away""Hayao Miyazaki")

  }


  
public Movie[] findAll() return MOVIES; }

}


 


然后创建一个 manifest 文件 BasicMovieFinder.mf

 

Manifest-Version:  1.0

Bundle-ManifestVersion: 
2

Bundle-Name: Basic Movie Finder

Bundle-SymbolicName: BasicMovieFinder

Bundle-Version: 
1.0.0

Import-Package: osgitut.movies
; version="[1.0.0,2.0.0)"

 

注意,我们导入了被另一个bundle导出的package osgitut.movies。同时我们在导入的时候添加了一个版本范围。框架将在运行时使用这个版本范围,检查导入的和被导出的package是否相匹配。OSGi对版本范围所使用的语法对于数学爱好者来说应该是很熟悉的:方括号表示包括,而圆括号表示不包括。这样,我们能很有效地表示出版本”1.x”

 


同样的,为导入的 package 添加版本号也不是必须的,但是,这是一个很好的习惯。

 


好,我们编译并创建第二个 bundle

 

javac -classpath MoviesInterface . jar osgitut / movies / impl / BasicMovieFinderImpl . java

jar -cfm BasicMovieFinder
. jar BasicMovieFinder . mf osgitut / movies / impl / * . class 

现在,我们终于可以在Equinox上测试这些bundle了。这一次,我们不再详细给出所有的指令了,你应该可以自己处理:)

首先,安装BasicMovieFinder,输入ss,应该能看到这个bundle处于INSTALLED状态;

 

id      State       Bundle

0        ACTIVE      org . eclipse . osgi_3 . 3.0 . v20070208

4        INSTALLED   BasicMovieFinder_1 . 0.0

 


(作者注:你的 bundle 列表看起来可能会和我的不一样。一般来说, bundle ID 取决于你上一次安装和卸载了多少次 HelloWorld J 你需要自己手动将文中的 ID 转换成你的 ID

 


INSTALLED 表示框架已经得到这个 bundle 了,但是还没有处理它的依赖性。强制 Enquinox 处理这些 bundle 的一个方法是调用 refresh 命令。所以,输入 refresh 4 后,你将看到:

 


id      State       Bundle

0        ACTIVE      org . eclipse . osgi_3 . 3.0 . v20070208

4        INSTALLED   BasicMovieFinder_1 . 0.0  

这个bundle还是不是RESOLVED。这是理所当然的,我们需要安装包含了Movie类和MovieFinder接口的“接口”bundle。为了确定这就是问题所在,输入diag 4来查看诊断信息:

 

file :BasicMovieFinder . jar [ 4 ]

  Missing imported package osgitut
. movies_[ 1.0 . 0 , 2.0 . 0 ).

 

看,这正是问题所在:我们无法导入package osgitut.movies,因为现在没有一个bundle导出这个package。现在,安装MovieInterface.jar bundle,并执行ss。新的列表应该是这样子:

id      State       Bundle

0        ACTIVE      org . eclipse . osgi_3 . 3.0 . v20070208

4        INSTALLED   BasicMovieFinder_1 . 0.0

5        INSTALLED   MoviesInterface_1 . 0.0  

最后的步骤是让Equinox再次处理BasicMovieFinder。输入refresh 4,将看到:

id      State       Bundle

0        ACTIVE      org . eclipse . osgi_3 . 3.0 . v20070208

4        RESOLVED    BasicMovieFinder_1 . 0.0

5        RESOLVED    MoviesInterface_1 . 0.0

 

好了,现在BasicMovieFinderRESOLVED状态了。这是一个很重要的步骤,因为只有当一个bundleRESOLVED状态,他才可以被启动,或者为其它bundle提供依赖。

 


注意,通常并不需要象这样手动处理。一般的, bundle 会在需要时自动被处理。例如,本例中,尽管我们没有明确要求 refresh MovieInterface 已经是 RESOLVED 状态了。


以上就是今天的内容。你可以去看看这篇文章“Chris Aniszczyk's excellent article on IBM developerWorks(http://www-128.ibm.com/developerworks/opensource/library/os-ecl-osgiconsole/),看看通过Equinox控制台可以做哪些好玩的事情:)

 

下一次,我们将介绍OSGi 服务。

 

------------------- 重要的回帖 ----------------------

Eclipse中启动OSGi平台的方法是,菜单”Run”->”Run…”,创建一个新的运行选项,在左边的列表中选择”OSGi Framework”

OSGi起步(3):bundle之间的依赖_第1张图片

这样,当你运行这个配置的时候,你将在Eclipse界面的控制台窗口中看到OSGi的控制台。

(译者:我的尝试出错了-___-!

你可能感兴趣的:(编程相关,翻译新手)