OSGi服务发布和获取方式

来源:互联网 发布:js的insertbefore参数 编辑:程序博客网 时间:2024/05/09 11:14

OSGi服务发布和获取方式

来源: http://www.xymyeah.com/233.html


一、OSGi服务发布和获取方式有如下种类

1、最原始方式

      ==

        // 获取Service引用
        ServiceReference ref = context.getServiceReference(LogService.class.getName());
        if (ref != null) {
             // 获取Service实例
             LogService service = (LogService) context.getService(ref);
             if (service != null) {
                // 调用Service方法
                service.log(LogService.LOG_INFO, "ok");
                 // 释放Service,在此之后不应该再继续使用Service实例
                context.ungetService(ref);
             }
         }

     ==

     优点:逻辑够简单,适合一次性操作
     缺点:
           1)、OSGi的动态性无法保证获取的ref长期有效
           2)、每次访问都需要手动释放service
           3)、过于依赖bundle的启动顺序

     使用场合:不频繁的调用service,如只调用一次的情况


2、Listener方式

      ==

      //在Service注册时访问:

        context.addServiceListener(new ServiceListener() {
            public void serviceChanged(ServiceEvent event) {
                switch (event.getType()) {
                case ServiceEvent.REGISTERED:
                     // 获取Service引用
                    ServiceReference ref = event.getServiceReference();
                    // 获取Service实例
                     LogService service = (LogService) context.getService(ref);
                     if (service != null) {
                          // 调用Service方法
                          service.log(LogService.LOG_INFO, "ok");
                           // 释放Service,在此之后不应该再继续使用Service实例
                          context.ungetService(ref);
                      }
                    break;
                 case ServiceEvent.UNREGISTERING:
                    break;
                }
             }
        }, "(objectclass=org.osgi.service.log.LogService)");

      ==

        //独立于ServiceListener的访问:类似于方式一,在Listener中获取service并且保存到成员变量中,以供后续访问:

        context.addServiceListener(new ServiceListener() {
             public void serviceChanged(ServiceEvent event) {
                 switch (event.getType()) {
                 case ServiceEvent.REGISTERED:
                    if (ref == null) {
                        ref = event.getServiceReference();
                         service = (LogService) context.getService(ref);//保存实例以备后续访问
                    }
                     break;
                  case ServiceEvent.UNREGISTERING:
                     if (ref == event.getServiceReference()) {
                         context.ungetService(ref);//释放实例
                         service = null;
                         ref = null;
                     }
                     break;
                 }
 
             }
        }, "(objectclass=org.osgi.service.log.LogService)");

        //访问Service:

        if (service != null) service.log(LogService.LOG_INFO, "ok");

      ==

     优点:只在Service变更时产生一次service获取开销,动态感知service的注册和注销。
     缺点:
          1)、在listener起来之前的服务无法监听
          2)、需要维护service的获取和释放
          3)、监听多个 Service实例时,使用并不方便
     使用场合:不推荐使用

 

3、serviceTracker方式

     ServiceTracker其实是对ServiceListener实现方式的封装,使得对service的获取更加简洁,同时也解决了不能监听到已经存在的Service的问题(其实就是在增加ServiceListener的同时调用BundleContext.getAllServiceReferences方法以获取现有的Service引用)。

      ==

        //一次性访问:

        ServiceTracker tracker = new ServiceTracker(context, LogService.class.getName(), null);
        tracker.open();
        LogService service = (LogService) tracker.getService();
         if (service != null) service.log(LogService.LOG_INFO, "ok");
         // 获取多个Service
        Object[] services = tracker.getServices();
        // 获取Service的数量
         int count = tracker.getTrackingCount();
        tracker.close();

      ==

      //在Service注册和注销时访问:

         ServiceTracker tracker = new ServiceTracker(context, LogService.class.getName(), null) {
             @Override
             public Object addingService(ServiceReference reference) {
                 LogService service = (LogService) super.addingService(reference);
                 if (service != null) service.log(LogService.LOG_INFO, "ok");
                 return service;
             }
 
             @Override
             public void removedService(ServiceReference reference, Object service) {
                 ((LogService) service).log(LogService.LOG_INFO, "removedService");
                 super.removedService(reference, service);
             }
         };
         tracker.open();
 
         // 在自身lifecycle结束时关闭tracker
         tracker.close();

      ==

     有一点需要注意的是,tracker需要调用open方法才能监听到Service,另外,在bundle stop以后,bundle内open的ServiceTracker不会自动关闭,所以一定不要忘记在bundle结束之前,关闭所有在bundle中open的ServiceTracker。

 

     优点:不必再考虑Service是否存在的问题
     缺点:bundle stop以后,bundle内open的ServiceTracker不会自动关闭
     使用场合:不推荐使用


4、DS(Declarative Service)

     在OSGi 4以后的规范中,增加了Declarative Services方式。Declarative Services 是一个面向服务的组件模型,它制订的目的是更方便地在 OSGi服务平台上发布、查找、绑定服务,对服务进行动态管理,如监控服务状态以及解决服务之间的复杂的依赖关系等问题。DeclarativeServices 采用服务组件的延迟加载以及组件生命周期管理的方式来控制对于内存的占用以及启动的快速,很好的解决了传统的 OSGi服务模型在开发和部署比较复杂应用时内存占用大、启动慢等问题,并且对服务组件的描述采用XML来实现,十分便于用户理解和使用。

     在equinox-SDK-3.6M5开发包中,包含了一个DS的实现:org.eclipse.equinox.ds_1.2.0.v20100125.jar,将这个jar和一个依赖的jar:org.eclipse.equinox.util_1.0.100.v20090520-1800.jar部署到OSGi容器中,就可以使用DS服务了。equinox中DS服务的实现,是综合使用了BundleListener,ServiceListener等相关OSGi API,将大量繁杂和冗长的代码细节藏在了实现背后,开发者只需要了解简单的xml语法和配置方式即可方便的使用。
要使用DS,一般有以下几个步骤:
      ==

      //1.定义Component实现类:

       package org.dbstar.osgi.dstest;

       import org.osgi.service.component.ComponentContext;
       import org.osgi.service.log.LogService;
 
       public class TestComponent {
           public void activate(ComponentContext context) {
               System.out.println("activate(" + context + ")");
           }
 
           public void deactivate(ComponentContext context) {
               System.out.println("deactivate(" + context + ")");
           }
 
           public void modified(ComponentContext context) {
               System.out.println("modified(" + context + ")");
           }
 
           public void bind(LogService service) {
               service.log(LogService.LOG_INFO, "bind");
           }
 
           public void unbind(LogService service) {
               service.log(LogService.LOG_INFO, "unbind");
           }
       }

      ==

       //2.编写component.xml:

       <?xml version="1.0" encoding="UTF-8"?>
       <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
           activate="activate" deactivate="deactivate" modified="modified" name="test"
           xsi:schemaLocation="http://www.osgi.org/xmlns/scr/v1.1.0 http://www.osgi.org/xmlns/scr/v1.1.0">
           <implementation class="org.dbstar.osgi.dstest.TestComponent" />
           <reference bind="bind" cardinality="1..1"
               interface="org.osgi.service.log.LogService" name="LogService"
               policy="dynamic" unbind="unbind" />
      </scr:component>

      ==

      以上是有namespace的xml写法,在equinox中也支持没有namespace的写法,Eclipse中有相应的插件来提供图形化的界面来维护component xml。以下是没有namespace的xml写法:

       <?xml version="1.0" encoding="UTF-8"?>
      <component name="test">
           <implementation class="org.dbstar.osgi.dstest.TestComponent" />
           <reference bind="bind" cardinality="1..1"
               interface="org.osgi.service.log.LogService" name="LogService"
               policy="dynamic" unbind="unbind" />
       </component>

      ==

      3.将写好的xml放置到bundle根目录下的OSGI-INF下面
      4.在bundle的描述文件META-INF/MANIFEST.MF中增加component相关的header:

         Service-Component: OSGI-INF/component.xml

      ==

      注意xml的文件名不是绝对的,放置的目录也不是绝对的,只要在Service-Component中包含正确的路径就可以了。
      一个bundle可以注册多个component,只要编写多个xml文件即可,在Service-Component中以逗号分隔。
      Component的注册并不依赖Activator,所以bundle的Activator不是必须的。
      另外在我的使用过程中,发现一个问题,如果xml中没有使用namespace,那么component节点上的几个callback类属性都不能定义,例如activate属性。如果使用了namespace,那么这些属性都是可以正常使用的,不知道这算不算是bug。
      关于DS规范的详细内容,可以参见:OSGi 中的 Declarative Services 规范简介


     优点:
          1)、通过配置发布获取服务
          2)、采用服务组件的延迟加载以及组件生命周期管理的方式来控制对于内存的占用以及启动的快速
     缺点:与其他用spring开发项目不好集成

 

5、Spring-DM(spring dynamic modules)

      ==

 

      ==

     优点:
          1)、spring的方式管理对象(Dependency Injection方式)
          2)、通过配置发布获取服务
          3)、与其他spring项目容易集成
     缺点:

6、Blueprint

      ==

 

      ==

     优点:
          1)、spring的方式管理对象(Dependency Injection方式)
          2)、通过配置发布获取服务
          3)、与其他spring项目容易集成
          4)、发布获取方式更加灵活
      缺点:

二、Spring Dynamic Modules for OSGi 和 OSGi Blueprint的关系

1、Spring  Dynamic Modules for OSGi:

          1)、定义了一套用Spring DI 的方式来注册OSGi Service 和引用OSGi Service;

          2)、用户再也不用写代码来注册和查找Service了;

          3)、SpringDM 1.x实现了Spring Dynamic Modules for OSGi技术;

 

2、OSGi 4.2 规范定义了Blueprint:

          1)、该技术其实就是Spring Dynamic Modules的演化和标准化;

          2)、SpringDM 2.x就是Blueprint的一个参考实现。


 http://www.xymyeah.com/233.html



原创粉丝点击