编写第一个OSGI的小demo

开发一个真实的 OSGi 应用程序

我们不能只停留在 hello world 的层面,虽然那曾经对我们很重要 ,但是现实需要我们能够使用 OSGi 写出激动人心的应用程序,它能够被客户接受,被架构师认可,被程序员肯定。好的,那我们开始吧。下面将会着重介绍一些现实的应用程序可能需要的一些 OSGi 应用场景。

发布和使用服务

由于 OSGi 框架能够方便的隐藏实现类,所以对外提供接口是很自然的事情,OSGi 框架提供了服务的注册和查询功能。好的,那么我们实际操作一下,就在 Hello world 工程的基础上进行。

我们需要进行下列的步骤:

  1. 定义一个服务接口,并且 export 出去供其它 bundle 使用;
  2. 定义一个缺省的服务实现,并且隐藏它的实现;
  3. Bundle 启动后,需要将服务注册到 Equinox 框架;
  4. 从框架查询这个服务,并且测试可用性。

好的,为了达到上述要求,我们实际操作如下:

  1. 定义一个新的包 osgi.test.helloworld.service ,用来存放接口。单独一个 package 的好处是,您可以仅仅 export 这个 package 给其它 bundle 而隐藏所有的实现类
  2. 在上述的包中新建接口 IHello,提供一个简单的字符串服务,代码如下:
    清单 2. IHello
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package osgi.test.helloworld.service;
     
    public interface IHello {
         /**
          * 得到 hello 信息的接口 .
          * @return the hello string.
          */
         String getHello();
    }
  3. 再新建一个新的包 osgi.test.helloworld.impl,用来存放实现类。
  4. 在上述包中新建 DefaultHelloServiceImpl 类,实现上述接口:
    清单 3. IHello 接口实现
    1
    2
    3
    4
    5
    6
    7
    8
    public class DefaultHelloServiceImpl implements IHello {
     
         @Override
         public String getHello() {
             return "Hello osgi,service";
         }
     
      }
  5. 注册服务,OSGi 框架提供了两种注册方式,都是通过 BundleContext 类实现的:
    1. registerService(String,Object,Dictionary) 注册服务对象 object 到接口名 String 下,可以携带一个属性字典Dictionary
    2. registerService(String[],Object,Dictionary) 注册服务对象 object 到接口名数组 String[] 下,可以携带一个属性字典 Dictionary,即一个服务对象可以按照多个接口名字注册,因为类可以实现多个接口;

    我们使用第一种注册方式,修改 Activator 类的 start 方法,加入注册代码:

    清单 4. 加入注册代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void start(BundleContext context) throws Exception {
             
         System.out.println("hello world");
         context.registerService(
             IHello.class.getName(),
             new DefaultHelloServiceImpl(),
             null);
             
    }
  6. 为了让我们的服务能够被其它 bundle 使用,必须在 MANIFEST.MF 中对其进行导出声明,双击 MANIFEST.MF,找到runtime > exported packages > 点击 add,如图,选择 service 包即可:
    图 14. 选择导出的服务包
    图 14. 选择导出的服务包
  7. 另外新建一个类似于 hello world 的 bundle 叫:osgi.test.helloworld2,用于测试 osgi.test.helloworld bundle 提供的服务的可用性;
  8. 添加 import package:在第二个 bundle 的 MANIFEST.MF 文件中,找到 dependencies > Imported packages > Add …,选择我们刚才 export 出去的 osgi.test.helloworld.service 包:
    图 15. 选择刚才 export 出去的 osgi.test.helloworld.service 包
    图 15. 选择刚才 export 出去的 osgi.test.helloworld.service 包
  9. 查询服务:同样,OSGi 框架提供了两种查询服务的引用 ServiceReference 的方法:
    1. getServiceReference(String):根据接口的名字得到服务的引用;
    2. getServiceReferences(String,String):根据接口名和另外一个过滤器名字对应的过滤器得到服务的引用;
  10. 这里我们使用第一种查询的方法,在 osgi.test.helloworld2 bundle 的 Activator 的 start 方法加入查询和测试语句:
    清单 5. 加入查询和测试语句
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void start(BundleContext context) throws Exception {
         System.out.println("hello world2");
             
         /**
             * Test hello service from bundle1.
         */
         IHello hello1 =
             (IHello) context.getService(
             context.getServiceReference(IHello.class.getName()));
             System.out.println(hello1.getHello());
    }
  11. 修改运行环境,因为我们增加了一个 bundle,所以说也需要在运行配置中加入对新的 bundle 的配置信息,如下图所示:
    图 16. 加入对新的 bundle 的配置信息
    图 16. 加入对新的 bundle 的配置信息
  12. 执行,得到下列结果:
    图 17. 执行结果
    图 17. 执行结果

恭喜您,成功了!


### OSGi 架构 示例代码 #### 创建简单OSGi 束 (Bundle) 为了创建一个基本的 OSGi 应用程序,首先需要定义两个主要部分:提供服务的服务端和服务消费者客户端。 ##### 1. 定义接口 `GreetingService` ```java package org.example.service; public interface GreetingService { String greet(String name); } ``` ##### 2. 实现服务 `SimpleGreetingServiceImpl` ```java package org.example.impl; import org.example.service.GreetingService; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; public class SimpleGreetingServiceImpl implements GreetingService, BundleActivator { private ServiceRegistration<GreetingService> registration; @Override public void start(BundleContext context) throws Exception { System.out.println("Starting the greeting service..."); registration = context.registerService(GreetingService.class, this, null); } @Override public void stop(BundleContext context) throws Exception { System.out.println("Stopping the greeting service..."); if (registration != null) { registration.unregister(); } } @Override public String greet(String name) { return "Hello, " + name; } } ``` ##### 3. 编写客户端来消费该服务 ```java package org.example.client; import org.example.service.GreetingService; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; public class ClientActivator implements BundleActivator { private ServiceTracker<GreetingService, GreetingService> tracker; @Override public void start(BundleContext context) throws Exception { System.out.println("Client starting..."); // Track and get an instance of our service when it becomes available. tracker = new ServiceTracker<>(context, GreetingService.class, null); tracker.open(); GreetingService service = tracker.getService(); if (service != null) { System.out.println(service.greet("World")); } else { System.out.println("No greeting service found."); } } @Override public void stop(BundleContext context) throws Exception { System.out.println("Client stopping..."); if (tracker != null) { tracker.close(); } } } ``` 上述例子展示了如何在一个典型的 OSGi 环境下定义、发布以及使用服务[^2]。此案例中,`SimpleGreetingServiceImpl` 类实现了 `GreetingService` 接口,并作为 OSGi 服务被注册到了框架内;与此同时,另一个 bundle (`ClientActivator`) 则负责追踪并调用了这个已发布的服务实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值