OSGi起步(5):使用服务

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

原地址:http://www.eclipsezone.com/eclipse/forums/t90796.html

原作者:Neil Bartlett

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

OSGi起步(5):使用服务

 

上一部分,我们知道了如何注册一个服务。这一次,我们来看看怎么去查找和使用另一个bundle注册的服务。

 

和以前一样,我们使用Martin Fowler关于“依赖注入”的论文里提到的例子。我们已经创建了一个MovieFinder,并且把它做为服务注册到注册表中。现在,我们来创建一个MovieLister,它将使用MovieFinder来查找某个导演执导的影片。我们假设MovieLister本身也是一个服务,它将被其他bundle使用,比如一个用户界面程序。这就有麻烦了,因为OSGi的服务是动态的,它们存在与否都是可能的。这意味着,有时候我们想去调用MovieFinder服务,却意外地发现它并不可用!

 

MovieFinder服务不存在的时候,MovieLister该怎么处理呢?很显然,调用MovieFinderMovieLister很重要的一个工作,所以我们只有很少的几个可选的选项:

1、返回一个错误,比如,返回null或者抛出一个异常;

2、等待;

3、一开始就不出现。

本文中,我们将把注意力集中在前两个选项上,因为它们比较简单。一开始,你可能会觉得第三个选项没有任何意义。不过,在我们实现前两种方法以后,它会变得很让人期待。

 

我们要做的第一件事是,为MovieLister定义一个接口。复制以下代码到osgitut/movies/MovieLister.java:

 

package  osgitut.movies;

import  java.util.List;

public   interface  MovieLister  {

    List listByDirector(String name);

}
 

接着,创建文件 osgitut/movies/impl/MovieListerImpl.java:

package  osgitut.movies.impl;

import  java.util. * ;

import  osgitut.movies. * ;

import  org.osgi.framework. * ;

import  org.osgi.util.tracker.ServiceTracker;

public   class  MovieListerImpl  implements  MovieLister  {

    
private final ServiceTracker finderTrack;

    
public MovieListerImpl(ServiceTracker finderTrack) {

        
this.finderTrack = finderTrack;

    }


    
public List listByDirector(String name) {

        MovieFinder finder 
= (MovieFinder) finderTrack.getService();

        
if(finder == null{

            
return null;

        }
 else {

            
return doSearch(name, finder);

        }


    }


 
    
private List doSearch(String name, MovieFinder finder) {

        Movie[] movies 
= finder.findAll();

        List result 
= new LinkedList();

        
for (int i = 0; i < movies.length; i++{

            
if(movies[i].getDirector().indexOf(name) > -1{

                result.add(movies[i]);

            }


        }


        
return result;

    }


}


这大概是到目前为止我们所写的最长的代码了。那么这些代码在做什么呢?首先,我们注意到,为了与OSGi相关的代码保持松散结构,查找电影的实际过程被提取到了doSearch(String ,MovieFinder)方法中。虽然,我们所用的查找方法很差而且没有效率,不过,做为一个教程,这倒是不重要。而且,数据库中只有两部电影:)

 
listByDirector(String name)
方法很有意思,它使用ServerTracker对象从服务注册表中获取MovieFinderServiceTracker是一个很有用的类,它掩盖了OSGi API底层许多乏味的细节。但是,我们仍然需要检查一个服务是否确实存在。我们假设ServiceTracker将在构造函数中传入。

bundler的控制器(activator)中创建ServiceTracker是一个不错的主意。复制以下代码到osgitut/movies/impl/MovieListerActivator.java

package  osgitut.movies.impl;

import  java.util. * ;

import  org.osgi.framework. * ;

import  org.osgi.util.tracker.ServiceTracker;

import  osgitut.movies. * ;

public   class  MovieListerActivator  implements  BundleActivator  {

    
private ServiceTracker finderTracker;

    
private ServiceRegistration listerReg;

    
public void start(BundleContext context) throws Exception {

        
// Create and open the MovieFinder ServiceTracker

        finderTracker 
= new ServiceTracker(context, MovieFinder.class.getName(), null);

        finderTracker.open();

        
// Create the MovieLister and register as a service

        MovieLister lister 
= new MovieListerImpl(finderTracker);

        listerReg 
= context.registerService(MovieLister.class.getName(), lister, null);

        
// Execute the sample search

        doSampleSearch(lister);

    }


    
public void stop(BundleContext context) throws Exception {

        
// Unregister the MovieLister service

        listerReg.unregister();

        
// Close the MovieFinder ServiceTracker

        finderTracker.close();

    }


    
private void doSampleSearch(MovieLister lister) {

        List movies 
= lister.listByDirector("Miyazaki");

        
if(movies == null{

            System.err.println(
"Could not retrieve movie list");

        }
 else {

            
for (Iterator it = movies.iterator(); it.hasNext();) {

                Movie movie 
= (Movie) it.next();

                System.out.println(
"Title: " + movie.getTitle());

            }


        }


    }


}
 

现在,这个activator开始变得有趣起来了。首先,在start方法中,创建了一个ServiceTracker(服务追踪器)对象,它将被我们刚刚写的MovieLister使用。接着,这个“追踪器”被“释放”,并开始在注册表中查找MovieFinder服务。然后它创建MovieListerImpl对象,并把它以“MovieLister”注册到服务注册表中。最后,为了在启动bundle的时候发生一些有趣的事情,activator简单地搜索了一下MovieLister然后输出结果。

我们需要编译并安装这个bundle。这一次,我不再给出完整的指令。你应该能够根据之前所做的实现这个操作。记住,你还需要创建一个manifest文件,并指明它的Bundle-Activatorosgitut.movies.impl.MovieListerActivator。另外,Import-package一行应该包含三个从其它bundle导入的package,分别是:org.osgi.framework, org.osgi.uitl.trackerosgitut.movies.

一旦你把MovieLister.jar安装到Equinox的运行环境中,你就可以启动它了。这时,你将看到两条或者三条消息,这取决于BasicMovieFinder bundle自从上一次起是否还在继续运行。如果没有,你将看到:

osgi> start  2

Could not retrieve movie list

如果在运行,将看到

osgi >  start  2

Title: Spirited Away
 

停止或者启动不同的bundle,你将看到你希望的每一条消息。这差不多就是本次要讲的所有内容了,除了我刚才说的,当一个服务不可用的时候,你还可以选择等待。由现有的代码,应该是很容易实现的:把MovieListerImpl的第16行的getService()改为调用ServiceTrackerwaitForService(5000),然后添加try/catch块来处理异常InterruptedException

 
一般来说,我不建议像这样子将一个线程挂起。这种情况是很危险的,因为listByDirector()方法是由bundleactivatorstart方法调用的,而它将被框架线程调用。activator通常被要求快速返回,因为当一个bundle处于活动状态的时候,将有一系列的事情发生。事实上,在最坏的情况下,还可能产生死锁,因为我们进入了到框架所拥有的一个对象的synchronized(同步)段中,而这个对象很可能已经被别的东西给阻塞了。一个比较好的建议是,永远不要再一个bundleactivatorstart方法中,或者直接被框架调用的代码中,进行长时间的操作和阻塞。

 
下一次,我们将看看当依赖不存在的时候,如何实现第三种方法:“一开始就不出现”。不要走开。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值