OSGI中ServiceTracker的应用

OSGI中ServiceTracker的应用



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


    /**
     * Create a {@code ServiceTracker} on the specified class name.
     *
     * <p>
     * Services registered under the specified class name will be tracked by
     * this {@code ServiceTracker}.
     *
     * @param context The {@code BundleContext} against which the tracking is
     *        done.
     * @param clazz The class name of the services to be tracked.
     * @param customizer The customizer object to call when services are added,
     *        modified, or removed in this {@code ServiceTracker}. If customizer
     *        is {@code null}, then this {@code ServiceTracker} will be used as
     *        the {@code ServiceTrackerCustomizer} and this
     *        {@code ServiceTracker} will call the
     *        {@code ServiceTrackerCustomizer} methods on itself.
     */
    public ServiceTracker(final BundleContext context, final String clazz, final ServiceTrackerCustomizer<S, T> customizer) {
        this.context = context;
        this.trackReference = null;
        this.trackClass = clazz;
        this.customizer = (customizer == null) ? this : customizer;
        // we call clazz.toString to verify clazz is non-null!
        this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")";
        try {
            this.filter = context.createFilter(listenerFilter);
        } catch (InvalidSyntaxException e) {
            /*
             * we could only get this exception if the clazz argument was
             * malformed
             */
            IllegalArgumentException iae = new IllegalArgumentException("unexpected InvalidSyntaxException: " + e.getMessage());
            iae.initCause(e);
            throw iae;
        }
    }

在上述源码中可以看到在ServiceTracker的构造方法中,这一行代码确定了监听那个服务:

this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")";

下一行则创建了相应的监听器,并对服务进行了监听,如下:

this.filter = context.createFilter(listenerFilter);

在我们进行相应服务的使用的时候,在进行使用ServiceTracker的时候,这个时候就对相应的服务进行了监听,在稍后演示过程中再进行程序的调试的时候,再来对具体进行分析。


ServiceTracker源码

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;
    }
}

HelloServiceTracker:

package cn.com.example;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;

/**
 * Created by xiaxuan on 16/7/12.
 */
public class HelloServiceTracker extends ServiceTracker {

    public HelloServiceTracker(BundleContext context) {
        super(context, HelloService.class, null);
    }

    @Override
    public Object addingService(ServiceReference reference) {
        System.out.println("adding service: " + reference.getBundle().getSymbolicName());
        return super.addingService(reference);
    }

    @Override
    public void removedService(ServiceReference reference, Object service) {
        System.out.println("removeing service: " + reference.getBundle().getSymbolicName());
        super.removedService(reference, service);
    }
}

Activator:

package cn.com.example;

import cn.com.ds.Test;
import cn.com.ds.TestComponent;
import org.osgi.framework.*;

/**
 * Created by Administrator on 2016/6/18.
 */
public class Activator implements BundleActivator {

    HelloServiceTracker serviceTracker;
    ServiceRegistration serviceRegistration;

    public void start(BundleContext bundleContext) throws Exception {
        System.out.println("service registered...");
        //开启服务跟踪器
        serviceTracker = new HelloServiceTracker(bundleContext);
        serviceTracker.open();
        //注册服务
        serviceRegistration = bundleContext.registerService(HelloService.class, new HelloServiceImpl(), null);
        //获取b被跟踪的服务
        HelloService helloService = (HelloService) serviceTracker.getService();
        if (helloService != null) {
            System.out.println(helloService.hello("xiaxuan"));
        }
        ServiceReference serviceReference = bundleContext.getServiceReference(Test.class);
        Test testComponent = (Test) bundleContext.getService(serviceReference);
        System.out.println(testComponent.hello("bingwen"));
    }

    public void stop(BundleContext bundleContext) throws Exception {
        System.out.println("Stopping service");
        //关闭服务跟踪器
        if (serviceTracker != null) {
            serviceTracker.close();
        }
        //注销服务
        serviceRegistration.unregister();
    }

}

演示

本次的演示还是和之前的一样,先启动bundle,然后再stop bundle后,再启动Bundle进入断点进行调试,查看断点时相关变量的状况,首先启动bundle,在karaf控制台中观察如下:

id为10的bundle,example启动成功,dankaraf控制台中,可以看到还有id为18的一个Bundle在命名风格上与example差不多,这个将会是在后续中将要讲到的,到时候将会在ds中提供ds服务和在Bundle之间进行event通信,这个在这里暂且提一下,后续两篇博文将会讲到这些。

现在停止这个bundle,然后再次start,进入断点查看我们在ServiceTracker中大的断点的情况,如下所示:

此时我将断点打到ServiceTracker中的构造方法中的listenerFilter的初始化处,此时观察listenerFilter监听的class,如下图:

可以看到clazz就是我们先前传入的LogService,在随后创建的filter中,将会对这个filter进行监听,在程序中的ServiceTracker的对监听方法的获取中,如下图所示:

获取服务的时候先从缓存中获取,然后cacheService为null,这里应该是在第一次中获取服务之后,边将对应service的引用存储在缓存中,随后在其后使用相应service的时候直接从cache中获取就可以了,没有从cache中拿到的时候,从getServiceReference()方法中获取,这个方法就不再讲解了,比较简单,就是首先cache中获取,如果获取到然后得到所有的ServiceReference后遍历,得到所需。


总结

  • 使用ServiceTracker使得获取Service的代码更加简洁和一致,不必再考虑Service是否存在的问题,并且ServiceTracker也提供了更加有效的监听Service的方式。
  • 有一点需要注意的是,tracker需要调用open方法才能监听到Service,另外,在bundle stop以后,bundle内open的ServiceTracker不会自动关闭,所以一定不要忘记在bundle结束之前,关闭所有在bundle中open的ServiceTracker。
  • 下一篇文章将开始讲解Declarative Services,即所谓的声明式服务。
时间: 2024-10-12 12:23:18

OSGI中ServiceTracker的应用的相关文章

OSGI中的service依赖关系管理

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

OSGI中Declarative Services的运用

OSGI中Declarative Services的运用 前言 Declarative Services,即所谓的声明式服务,我在前文中曾经提及到注册式服务与声明式服务,但是在前文中并没有提及怎么使用声明式服务,只是简单的说了下概念和相对于blueprint来说有哪些优缺点,总而言之,可谓是一笔带过,这几日想起这个,还是决定需要仔细的讲一下声明式服务. 简介 Declarative Services,这是在OSGi 4以后的规范中出现的,在这里引用一段其他人说的话,Declarative Ser

OSGi中的ServletContext

在OSGi中,不能的bundle分属不同的装载器(Class Loader), 在J2EE 应用中,不同BUNDLE 中的JSP 所对应的ServletContext对象不同,这与通常情况下的应用是不一样的. 一个例子如下: bundle a: [2014-07-22 11:08:21,335] SG-UAP : INFO Config:331 - --------------------------------------------------------- [2014-07-22 11:0

OSGI中自定义command(2)

OSGI中自定义command(2) 前文 在上一篇博文中,我们讲述了什么是OSGI中的command,同时写了一个简单的command,这个command实现了org.apache.felix.gogo.commands.Action这个接口,同样可以实现相同功能的还有 org.apache.karaf.shell.console.OsgiCommandSupport这一个抽象类,但是在本程序中,这两个接口或者抽象类上都标注了@Deprecated,因此已经不推荐使用了,而当前推荐使用的则是k

# OSGI中使用自定义的command

OSGI中command的应用 前文 在上一篇博文中,我们讲解了osgi中的blueprint,但并没有对此作出具体的运用,在本文及以后将会在讲osgi中其他应用的时候将blueprint串进来讲解,本文将要讲讲解的是osgi中的command,在编写的应用中,可能涉及到数据迁移或者其他一些操作,如果这个通过调用接口来进行操作的话,如果非相关人员获取到相关接口调用方式,可能会带来一些危害,所以在不得已的情况下不会使用接口的方式,这个时候command的作用就体现出来了,如果自己编写数个命令,然后

OSGI中blueprint简介

OSGI中blueprint简介 上篇博文我们开始了felix中的一个example编写,原本计划是讲felix中的几个example全部编写一遍,但是随后发现felix的这几个example都差不多,只是略微有些区别,编写来编写去始终都是这几行代码,讲起来也没什么意思,想着还是开始osgi中新的东西的讲解,思考来去,还是从blueprint开始. blueprint简介 在osgi中服务的使用有多种方式,如使用传统的注册式服务,就是我们之前中example不断使用的使用方式,还是osgi中的声

ofbiz,普通java程序,osgi中类加载

OSGI中类加载 在osgi中,存在多个类加载器,每一个类加载器加载一个独立的模块,当其他模块需要寻找这个类时,通过osgi框架依赖关系表去查找这个类所在的加载器,委托这个加载器去运行 ofbiz中类加载 ofbiz中集成了许多应用程序,像订单,安全,登陆,网店等,还有tomcat也被集成到ofbiz中,在ofbiz中是通过将这些应用程序的jar包和资源文件加载到同一个类加载器中(包括tomcat) 普通java程序 和ofbiz中类加载器一致

osgi中第三方bundle的问题

2015年1月20日写到: OSGi常见问题总结 :http://blog.csdn.net/ostrichmyself/article/details/7515653IBM的另一个场景:http://www-01.ibm.com/support/docview.wss?uid=swg21568564一个很多的文档:http://www.bouncycastle.org/specifications.html 头疼的问题:银联给了个jar包,upacp_sdk-1.0.0.jar 此包用于签名,

OSGI项目中获取文件路径

如果想根据给定的文件名称创建一个File实例,你可能会这么写: File file = new File(当前类.class.getResource("config").toURI()); 但是在osgi项目中,这种写法会报异常,异常信息是URI scheme is not "file",原因是osgi中采用的是bundleresources协议的URL,得到的URI中包含了"bundleresource://165xxxxxxxx/"前缀,所以