osgi之ServiceListener的应用

osgi之ServiceListener的应用


前言

我原想直接跳过这些osgi中基础知识,直接从osgi应用的一些中级篇或者高级篇开始的,后来想到osgi中的ServiceListener、ServiceTracker、Ds还是都需要讲一下,所以决定将osgicommand后续中的内容放一下,从ServiceListener开始讲一下,不过这里就不再讲述felix官网中的ServiceListener的example,而是自己单独编写example和进行相关讲解。


ServiceListener

/**
 * A {@code ServiceEvent} listener. {@code ServiceListener} is a
 * listener interface that may be implemented by a bundle developer. When a
 * {@code ServiceEvent} is fired, it is synchronously delivered to a
 * {@code ServiceListener}. The Framework may deliver
 * {@code ServiceEvent} objects to a {@code ServiceListener} out
 * of order and may concurrently call and/or reenter a
 * {@code ServiceListener}.
 *
 */

ServiceListener解释如上所示,本义就是这只是一个接口,在进行相应的实现之后,可以用来监控某些服务,在服务注册、修改、注销的时候,进行相应的其他调用,现在我将讲述这个ServiceListener的具体使用,在使用过程中,再来讲解中间会有那些问题。


ServiceListener用法1

先分别提供一个接口和一个实现类,分别为HelloService和HelloServiceImpl,代码如下:

HelloService:

package cn.com.example;

/**
 * Created by xiaxuan on 16/7/12.
 */
public interface HelloService {

    String hello(String name);
}

HelloServiceImpl:

package cn.com.example;

/**
 * Created by xiaxuan on 16/7/12.
 */
public class HelloServiceImpl implements HelloService {

    public String hello(String name) {
        return "hello " + name;
    }
}

都很简单,就是提供一个简单的服务,其中有一个方法为hello,真正的重点还是在Activator中,现在先贴出Activator中的代码,随后再来讲解其中监听服务和容易出现的问题:

package cn.com.example;

import org.osgi.framework.*;

/**
 * Created by xiaxuan on 16/7/12.
 */
public class Activator2 implements BundleActivator, ServiceListener {

    ServiceRegistration serviceRegistration;
    BundleContext context;

    public void start(BundleContext context) throws Exception {
        this.context = context;
        context.addServiceListener(this);
        System.out.println("service registered....");
        serviceRegistration = context.registerService(HelloService.class, new HelloServiceImpl(), null);
    }

    public void stop(BundleContext context) throws Exception {
        context.removeServiceListener(this);
        System.out.println("service unregistered...");
        serviceRegistration.unregister();
    }

    public void serviceChanged(ServiceEvent event) {
        switch (event.getType()) {
            case ServiceEvent.REGISTERED:
                //获取service引用
                ServiceReference ref  = context.getServiceReference(HelloService.class);
                //获取service实例
                HelloService helloService = (HelloService) context.getService(ref);
                if (helloService != null) {
                    //调用service方法
                    System.out.println(helloService.hello("xiaxuan"));
                    //释放service
                    context.ungetService(ref);
                }
                break;
            case ServiceEvent.UNREGISTERING:
                System.out.println("serviceChanged find service unregistered.");
                break;
        }
    }
}

我们在Activator中实现ServiceListener之后,还需要将自己本身加入到监听器中,在serviceChanged方法中,当服务出现变化的时候可以在这个方法中监听到,其中或是注册,注销,或是修改都可以做出监听,现在我们打上断点,监听相关服务。


服务启动

服务启动过程就不再截图了,这次我们在stop bundle,然后再start bundle的时候再来调试和查看相应的信息,现在展示karaf已经成功启动的截图,如下所示:

可以看到example这个Bundle已经正常启动,现在先使用stop命令,实质上在karaf中这个命令是Bundle:list命令,在karaf中大量的运用命令,在之后若有时间将会讲一下karaf的源码,讲一下这些命令,这个时候example的id为8,我们使用stop 8停止这个Bundle,执行命令之后如下所示:

当Bundle中的state为resolved的时候,这个Bundle已经停止下来了,然后我们再启动Bundle,命令为start 8,这个时候我们观察我们的断点,这个断点设置在serviceChanged方法中,如下所示:

我们放开断点,这个时候程序再次进入断点,如下:

发现这次进入断点的时候,event类型和上次有所不同,说明这里的ServiceListener的serviceChange方法对当前bundle启动的手,所有的服务注册都做了监听,这个时候,我们去掉断点,观察控制台,会发现打了许多次的’hello xiaxuan’,如下:

打了五次的hello xiaxuan,说明有五次的服务注册,每一次服务注册都进来获取了一次HelloService,然后调用了一次服务,在控制台打印一次,ServiceListener并没有对具体某个服务进行监听。


ServiceListener用法2

在以上ServiceListener的用法中,并不仅是在Activator中实现ServiceListener来做到监听服务,可以在start方法中直接实现,如果Activator类实现ServiceListener接口,还需要将本身加进Listener中,代码如下:

context.addServiceListener(this);

如果在start方法中实现的话,代码如下所示:

package cn.com.example;

import org.osgi.framework.*;

/**
 * Created by xiaxuan on 16/7/13.
 */
public class Activator3 implements BundleActivator {

    ServiceRegistration serviceRegistration;
    BundleContext context;

    public void start(BundleContext bundlecontext) throws Exception {
        this.context = bundlecontext;
        System.out.println("service registered....");
        serviceRegistration = context.registerService(HelloService.class, new HelloServiceImpl(), null);
        context.addServiceListener(new ServiceListener() {
            public void serviceChanged(ServiceEvent event) {
                switch (event.getType()) {
                    case ServiceEvent.REGISTERED:
                        //获取service引用
                        ServiceReference ref  = context.getServiceReference(HelloService.class);
                        //获取service实例
                        HelloService helloService = (HelloService) context.getService(ref);
                        if (helloService != null) {
                            //调用service方法
                            System.out.println(helloService.hello("xiaxuan"));
                            //释放service
                            context.ungetService(ref);
                        }
                        break;
                    case ServiceEvent.UNREGISTERING:
                        System.out.println("serviceChanged find service unregistered.");
                        break;
                }
            }
        });
    }

    public void stop(BundleContext context) throws Exception {
        System.out.println("service unregistered...");
        serviceRegistration.unregister();
    }
}

直接在addServiceListener中new ServiceListener,然后实现相关方法,相比较而言还简单一点,不过实现的效果相同。


总结

  • 使用ServiceListener时,只在Service发生相关变更的时候获取开销,可以动态感知service的注册和注销。
  • 但是问题在于在ServiceListener注册之前已经存在的Service无法监听到,需要自己维护service的获取和释放,如果需要监听多个service的话,十分不方便。
  • 只要是服务发生变更的时候就进行相关监听,其实在许多时候无需监听其他服务,有时候用起来比较麻烦。
  • 下一节中将讲解ServiceTracker,这是对ServiceListener的进一步封装,能够有效的监听我们所需的服务。
时间: 2024-10-09 00:23:31

osgi之ServiceListener的应用的相关文章

osgi实战学习之路:7. Service-2之ServiceListener

ServiceListener三种状态: ServiceEvent.REGISTERED ServiceEvent.MODIFIED ServiceEvent.UNREGISTERING 基于ServiceListener实现服务查找的demo Provider student-manage/Activator.java package com.demo.service; import java.util.Dictionary; import java.util.HashMap; import

全手工快速开发osgi应用的方法

意义:直接使用编辑器编辑所需Osgi的服务,速度快.效率高. OSGI容器:选择knopflerfish_osgi_5.1.0 (http://www.knopflerfish.org/),支持OSGI最新的R5标准. 方法: 1 在当前目录下编写Activator.java文件(不需要建立相应的包文件夹--省事),内容如下(这个参照Felix的tutorial) package tutorial.example1; import org.osgi.framework.BundleActivat

osgi + felix example1编写

在上篇博文中,我们搭建了osgi的整个运行环境,并将其他个别组件也整合了进来用于后续的开发,本播客系列将会将apache felix官网中example全部编写一遍,然后进行osgi后续的文章编写,如osgi command,blueprint,configAdmin等等,这些暂且放置一边,日后写博文的时候再谈. example模块 在上回建立的maven工程中,新建文件夹命名为Application,日后编写的应用模块都将放在这个文件夹之中,新建maven module 命名为example,

OSGI中的service依赖关系管理

众所周知,对于高动态高可扩展的应用,OSGI是一个非常好的平台.但是,也因此增加了复杂性,开发中对service的依赖变得复杂.这也是service的关系管理成为OSGI中一个非常重要的部分,我们来看看OSGI中service依赖关系管理的方式.篇幅原因,只关注发展历程,不具体介绍每个方式的详细实现细节. 概括的说,目前在OSGI中主要有以下几种service依赖关系管理的方法: 1. Service listener 2. Service binder 3. Dependency Manage

深入理解OSGI的模块化

定义 OSGI(Open Service Gateway Initiative)技术是面向Java的动态模型系统. OSGI框架实现了一个优雅.完整和动态地组件模型.应用程序(bundle)无需重新引导可以被远程安装.启动.升级和卸载. OSGi技术提供允许应用程序使用精炼.可重用和可协作的组件构建的标准化原语. 这些组件能够组装进一个应用和部署中. OSGi服务平台提供在多种网络设备上无需重启的动态改变构造的功能. 为了最小化耦合度和促使这些耦合度可管理,OSGi技术提供一种面向服务的架构,它

osgi + felix example3编写与使用服务的改进

osgi + felix example3编写与使用服务的改进 上一篇博文中我们提及了如何对一个服务进行注册,但在example2和example2b中都没有对这个服务进行相应的使用,在本文中将对这个服务进行使用相应的使用,在felix的官网中,对该服务的使用方法是对目前已经注册的bundle进行扫描,然后使用服务,但是个人觉得Activator这种启动bundle最好只有一个,并且本文搭建了一个完整的环境,部署多个Activator bundle也不现实,因此本文采用了其他方法. 思路 在本文

OSGI传统注册式服务与声明式服务

上一篇博文中我们编写了第二个简单的osgi的example,并编写了一个接口DictionaryService,并在Activator这个Bundle中实现了这个interface,并在start启动方法中进行了osgi服务的注册,但并没有使用这个服务,这一篇文章中并不讲解怎么使用这个已经注册的服务,但是会讲解服务的使用方式,一种为声明式服务,一种为传统注册式服务,以下就是开始讲解何为osgi的注册式服务与声明式服务. 传统注册式服务 传统方式下,我们注册服务都是在bundle的激活器(Acti

OSGI中ServiceTracker的应用

OSGI中ServiceTracker的应用 前文讲了ServiceListener,ServiceListener用于监听各种服务,但是如果要监听某一种服务的话,可能要花费一番功夫才能完成,但是我们可以使用osgi中另外一个监听服务的方式,就是ServiceTracker,这个在本质上是对ServiceListener的一种封装,对service的获取比ServiceListener比起来又简单许多,并且可以解决不能监听到已经存在的service的问题,先简单的看一下ServiceTracke

osgi应用使用桥接的方式打成war包部署在websphere上时遇到的与cxf相关的问题

原来我们的程序都是基于Equinox架构的,但是后面因为要实现打成war包在中间件中部署的需求,使用了eclipse官方提供的桥接方式实现. 桥接的部分后面有时间了我专门写一个文章来说,不明白的暂时请参考eclipse官方文档.这里主要说一下已经桥接成功,但是在使用CXF时遇到问题的情况. 本来在其他中间件里跑得好好的程序,一放到websphere_v8里,就各种报错,都是与axis2有关的,但是我们的项目并没有使用axis2,而是使用cxf. 报错类似如下(我有3个环境,每个报的错都不同,不过