`
switchlau
  • 浏览: 54107 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

(转) OSGi入门:消费一个服务[译]

阅读更多

http://230996.blog.chinajavaworld.com/entry/3690/0/

 

在我们的上个部分,我们看了如何注册一个服务。现在哦我们需要从另外的Bundle查找并使用服务。

我们将问题放到我们的需求的上下文中,那个通过Martin Fowler的依赖反转的页面获得的灵感。我们建立了一个MovieFinder的服务并通过Service Registry注册了它。现在我们想要建立使用了MovieFinder的一个MovieLister来搜索定向的电影。我们假定MovieLister它自己将是被其它Bundle消费的一个服务,例如一个GUI应用程序。问题是,OSGi服务是动态的……它们来去都是动态的。意思就是有时我们想要调用MovieFinder服务但是它恰巧无效。

所以,如果MovieFinder没有呈现,那么MovieLister将做什么?显然,通过MovieLister完成工作的重要部分是调用MovieFinder,所以这有一些有用的选择给我们:
[list=decimal]

  • 生成一个错误,例如返回null或者抛出一个异常
  • 等待
  • 在第一次里不要调用
    [/list]

    在这篇文章中我们将首先看前两项,它们十分简单。第三个选项可能甚至仍然没有什么感觉,但是看过前两个后你将会对它抱有希望。

    第一件事我们需要为MovieLister服务定义接口。复制以下代码到osgitut/movies/MovieLister.java文件中:
    1
    2
    3
    4
    5
    6
    7
    
    package osgitut.movies;
     
    import java.util.List;
     
    public interface MovieLister {
        List listByDirector(String name);
    }
    



    现在创建文件osgitut/movies/impl/MovieListerImpl.java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    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;
        }
    }
    



    这可能是我们的目前最长的代码样本!那么这里将要做什么?首先你注意搜索电影的实际的逻辑被分隔在doSearch(String, MovieFinder)方法中,来帮助我们隔离OSGi具体代码。偶然的,我们执行搜索的方式是相当的愚笨和低效率,但是这不是这节指导的重点。我们无论如何只有两个电影在数据库中!

    有趣的部分是在listByDirector(String name)方法中,使用了一个ServiceTracker对象来从Service Registry中获得MovieFinder。ServiceTracker是将最低级别的OSGi API中的大量令人不愉快的细节抽象出来的非常有用的类。然而我们仍然要检查服务是否确实存在。我们采取在我们的构造函数中传递给我们的ServiceTracker。

    注意,你可能见过其他地方的代码从Registry获得一个服务而不使用ServiceTracker。例如,它可能调用BundleContext使用getServiceReference和getService。可是这个代码你不得不写的十分复杂并且它不得不小心的自行清理。以我所见,放到低级别的API中处理的益处很少,并且有很多的问题。总是单独使用ServiceTracker更好。

    一个不错的创建ServiceTracker的地方是在Bundler的激活器中。复制这段代码到osgitut/movies/impl/MovieListerActivator.java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
    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());
                }
            }
        }
    }
    



    现在来看看这个激活器的启动。首先,在start方法中它创建了一个ServiceTracker对象,在我们刚写的MovieLister中使用。然后“打开”ServiceTracker告诉它启动跟踪Registry中MovieFinder服务的实例。之后,创建我们的MovieListerImpl对象并在Registry注册它到名为“MovieLister”的接口下。最后,为了在我们启动Bundle时看到有意思的事情,激活器靠MovieLister运行了一个简单的搜索并打印出结果。

    我们需要建立并安装这个Bundle。我这次将不给出完整的介绍——你可以复习一下上个部分并使它工作。记得你需要创建一个manifest文件,并且它指示osgitut.movies.impl.MovieListerActivator类为Bundle-Activator。并且Import-Package行需要包含三个包,名称是org.osgi.framework,org.osgi.util.tracker和osgitut.movies。

    一旦你已经安装了MovieLister.jar到Equinox运行时,你可以启动它。在那点上你将看到两条信息中的一条,依赖于是否这个BasicMovieFinder的Bundle在上一次一直在运行。如果它没有运行,你将看到:
    1
    2
    
    osgi> start 2
    Could not retrieve movie list
    


    但是如果它正在运行你将看到:
    1
    2
    
    osgi> start 2
    Title: Spirited Away
    


    通过停止和启动各个Bundle,你将能够显示任一信息。并且那些几乎是这部分的全部,除了记得我说过当一个服务无效时等待的事情?代码我们已经有了,这实际上是很琐碎的:简单的改变MovieListerImpl的16行来调用waitForService(5000)在ServiceTracker上代替getService(),并且添加try/catch块来捕捉InterruptedException。

    listByDirector()方法等待5000毫秒的原因是要等MovieFinder服务被显示出来。如果一个MovieFinder服务那时已经安装了,当然,如果它已经存在——我们将立即获得它来使用。

    通常,我们建议不要像这样挂起线程。特别在这种情况下,它可能很危险因为listByDirector()方法实际是从我们的Bundle激活器的start方法调用的,这是一个从框架线程调用的方法。
    激活器意味着要迅速地返回,因为当一个Bundle启动了的时候会有一定数量的其它事情。事实上最坏的情况下我们可能引起死锁,因为我们会进入一个在属于框架对象的synchronized块,那可能已经被其他的一些给锁定了。通常的做法是从不在Bundle激活器的start方法中处理任何长时间运行或者阻塞操作,或者在框架直接调用的代码不做任何操作。

    在下个部分中,我们将看看在使用应付神奇的第三个选项:“Don’t exist in the first place”。稍候!
  • 分享到:
    评论

    相关推荐

      OSGI 入门资料PDF

      Spring是一个流行的Java应用框架,OSGI与Spring的结合可以提供更强大的模块化能力。Spring Dynamic Modules(Spring-DM)是用于OSGI的Spring扩展,它使得Spring应用可以无缝地在OSGI环境中运行。通过Spring-DM,你...

      OSGi入门篇:服务层

      服务接口为服务消费者和提供者之间提供了一个明确的契约,保证了服务的实现可以动态替换,而不会影响服务的使用者。 2. 服务的注册和发现 当一个bundle(OSGi中的模块化包)中的服务实现类准备好提供服务时,它会...

      OSGi入门教程(OSGi Introduce)

      OSGi的核心概念是基于Java的模块化,它的主要目标是为各种设备提供一个开放的服务平台,包括室内设备、交通工具、移动电话等,用于管理和分发应用程序和服务。 OSGi的特点主要包括: 1. **插件化(Bundles)**:...

      OSGi入门篇:生命周期层

      OSGi(Open Services Gateway Initiative)是一个基于Java语言的服务平台,提供了一种动态化、模块化的应用程序架构。在OSGi架构中,整个生命周期管理是十分重要的组成部分,它保证了应用能够动态地进行安装、启动、...

      OSGI入门和例子

      OSGI的核心是其模块系统,称为"bundle",每个bundle都是一个独立的代码单元,有自己的类加载器,可以独立地加载、启动、停止和更新。这个框架的出现极大地改善了Java应用的复杂性管理和版本依赖问题。 标题"OSGI...

      Spring OSGi 入门.pdf

      - **导出OSGi服务:**可以将普通的Spring Bean导出为OSGi服务,示例中`&lt;osgi:service&gt;`元素定义了服务的实现类和服务接口。 #### 五、导出OSGi服务 - **将普通Spring Bean导出为OSGi服务:**如上所示,通过`&lt;osgi:...

      OSGi入门资料-初探OSGi 的全文

      OSGi的入门资料,网上找的,初探OSGi 的全文

      OSGi入门篇:模块层(by 静默虚空)

      在OSGi入门篇:模块层这篇文章中,作者静默虚空深入探讨了OSGi框架中模块层的基础知识以及设计模块层时OSGi联盟所做的考虑。OSGi模块层是框架中最基础的部分,它实现了Java的模块化特性,但又与Java现有的模块化特性...

      Spring OSGi 入门.rar

      例如,你可以创建一个简单的Spring OSGi应用,包含一个提供计算服务的bundle(CalculatorServiceBundle)和一个使用该服务的bundle(ClientBundle)。CalculatorServiceBundle提供一个实现了加法运算的接口和实现类...

      OSGI入门和整合Spring

      2. **创建OSGI服务**:在OSGI环境中,Spring的bean可以被声明为OSGI服务,这样其他bundle就可以通过服务注册表查找并消费这些服务。 3. **使用Declarative Services(DS)**:OSGI DS提供了一种声明式的方式来管理...

      tomcat嵌入OSGI容器

      此外,OSGI还提供了服务注册和发现机制,使得Bundle可以动态地提供和消费服务,增强了系统的可扩展性和可维护性。 **Tomcat与OSGI的整合:** 1. ** Felix或Equinox插件**:最常见的将OSGI引入Tomcat的方法是使用...

      深入理解OSGi:Equinox原理、应用与最佳实践.pdf

      OSGi(Open Service Gateway Initiative)是一个定义了Java应用程序如何组织和模块化以及如何动态发现、启动、停止、更新这些模块化组件的规范。Equinox是OSGi规范的一个实现,它是由Eclipse基金会开发的。本文将...

      精彩:OSGI入门以及提升

      实例代码部分通常会包含实际的OSGI应用示例,比如如何创建一个简单的服务提供者和消费者,或者展示如何在OSGI环境中实现AOP(面向切面编程)。通过这些例子,你可以更直观地理解OSGI的工作原理,并学会在项目中应用...

      spring-osgi 入门手册和代码

      Spring OSGi 是一个将 Spring 框架与 OSGi(Open Service Gateway Initiative)容器相结合的开源项目,旨在提供一种在 OSGi 环境下使用 Spring 的方式。OSGi 是一种模块化系统,它允许开发人员创建可热部署、可升级...

      OSGi 入门+进阶+实战

      1. **模块系统**:OSGi的核心是模块化,每个模块称为一个Bundle,它包含类、资源和元数据。Bundle之间通过导出和导入包来实现依赖关系。 2. **生命周期管理**:OSGi Bundle有启动、停止、安装、更新和卸载等状态,...

      OSGI资料,OSGI进阶,OSGI实战,OSGI入门和整合Spring

      4. **Aries SPI Fly**:一种用于将Spring应用转换为OSGI bundle的工具,保持原有Spring配置不变。 《OSGI_Opendoc.rar》可能包含更丰富的OSGI官方文档和其他资源,帮助深入理解OSGI规范和实现。 通过学习这些资料...

      spring osgi 入门

      2. **Scope配置**: 设置`scope="bundle"`表示为每个服务导入者创建一个新的服务实例。 3. **包导出**: 需要在MANIFEST.MF文件中通过`Export-Package`指令导出相关的包,以便其他Bundle可以访问这些服务。 **示例...

    Global site tag (gtag.js) - Google Analytics