上1篇博文中我们编写了第2个简单的osgi的example,并编写了1个接口DictionaryService,并在Activator这个Bundle中实现了这个interface,并在start启动方法中进行了osgi服务的注册,但并没有使用这个服务,这1篇文章中其实不讲授怎样使用这个已注册的服务,但是会讲授服务的使用方式,1种为声明式服务,1种为传统注册式服务,以下就是开始讲授作甚osgi的注册式服务与声明式服务。
传统方式下,我们注册服务都是在bundle的激活器(Activator)中使用BundleContext.registerService()方法完成的。而服务的获得需要通过BundleContext.getServiceReference()获得ServiceReference实例,进而使用BundleContext.getService()得到真实的服务实例。这类方式虽然能够完成服务的发布与使用,但是带来1定的问题,具体以下:
产生较多的样板式代码。OSGi的bundle是动态化的,伴随着bundle的安装和卸载,它所发布的服务也会动态地处于可用或不可用的状态,因此每次使用服务的时候,我们都需要借助BundleContext对象去服务注册中心查找,而不能通过1次查找,1劳永逸地持有服务对象的援用。虽然有ServiceListener和ServiceTracker帮助我们监听和跟踪服务的状态,但是整体而言这类方式较为繁琐且容易出错。
影响启动时间,服务在激活器中注册时,需要实例化所有要发布的服务对象,由于激活器的start()方法是同步调用的,所以会影响到全部利用的启动时间。
加大内存的占用,在激活器中注册服务时,我们需要实例化所有的服务对象,但是这些服务在利用运行期间,其实不1定会用到,这在无形中加大了内存的占用。
API依赖引发的平台侵入性。使用传统方式注册和使用服务,会用到大量的OSGi API,从而产生与OSGi平台的耦合,如果要将代码复用到非OSGi场景当中,需要较多的重构工作。
osgi是通过声明式服务来解决以上存在的问题的,声明式服务中引入了两个元素,构件(component)和元数据文件(metadata.xml)。构件是1个物理的、可替换的系统组成部份,它包装了实现体且提供了对1组服务接口的实现方法。构件本身必须相容于接口且实现接口,接口表示了驻留在构件内的成份所实现的服务。这些服务定义了的1个整合的行动,并从1些构件实例提供给其它客户端构件实例。在声明式服务中1个构件就对应了某1个构件实现类,这个类相当因而1个pojo(普通的Java对象),在这个类中我们可以注册服务、援用服务、构件属性配置等1些满足特定需求的操作,总之构件是服务的提供者和使用者。而元数据文件则是1个xml文件,在声明式服务中所有的元数据文件名称都为metadata.xml,在这个xml文件中我们可以根据需求配置构件的1些必须信息,且所配置的这些信息必须遵守声明式服务元数据规范。
声明式服务主要由4个部份组成,声明式服务容器部份、元数据解析部份、代码织入部份和打包成声明式服务bundle的插件部份。
这篇文章讲授了传统的注册式服务和声明式服务,注册式服务在前面1篇的博文中有所提及,在后文中还是有相应的使用,但在声明式服务上,后文中将会使用blueprint来代替,Blueprint规范来源于Spring Dynamic Modules项目,最早出现于R4.2企业规范当中。这个到了往后讲授blueprint的时候再具体讲授这些。