- 浏览: 1595928 次
- 性别:
文章分类
- 全部博客 (2929)
- 非技术 (18)
- Eclipse (11)
- JAVA (31)
- 正则表达式 (0)
- J2EE (4)
- DOS命令 (2)
- WEB前端 (52)
- JavaScript (69)
- 数据库 (8)
- 设计模式 (0)
- JFreechart (1)
- 操作系统 (1)
- 互联网 (10)
- EasyMock (1)
- jQuery (5)
- Struts2 (12)
- Spring (24)
- 浏览器 (16)
- OGNL (1)
- WebService (12)
- OSGi (14)
- 软件 (10)
- Tomcat (2)
- Ext (3)
- SiteMesh (2)
- 开源软件 (2)
- Hibernate (2)
- Quartz (6)
- iBatis (2)
最新评论
OSGi中获取Service的几种方式
在OSGi中,Service是动态管理的,OSGi容器提供的好几种获取和使用Service的方式,那么这几种方式各有什么优、缺点
呢,下面我们就以org.osgi.service.log.LogService为例来分别讲一讲。
一。最原始的方式:
2 ServiceReferenceref = context.getServiceReference(LogService. class .getName());
3 if (ref != null ){
4 // 获取Service实例
5 LogServiceservice = (LogService)context.getService(ref);
6 if (service != null ){
7 // 调用Service方法
8 service.log(LogService.LOG_INFO, " ok " );
9 // 释放Service,在此之后不应该再继续使用Service实例
10 context.ungetService(ref);
11 }
12 }
优点:很难说有什么优点,硬要说几句的话,那就是逻辑够简单,调用最少,适合一次性操作。
缺点:需要判断返回值是否为null,需要手动申请和释放service,由于OSGi的动态性,请在获取ref后尽快使用,无法保证ref长期有效。每
次访问都会有service获取和释放的开销。
用途:适合于不频繁的调用service,且在service不可用时也能继续执行后续操作的场景。
二。使用ServiceListener:
在Service注册时访问:
2 public void serviceChanged(ServiceEventevent){
3 switch (event.getType()){
4 case ServiceEvent.REGISTERED:
5 // 获取Service引用
6 ServiceReferenceref = event.getServiceReference();
7 // 获取Service实例
8 LogServiceservice = (LogService)context.getService(ref);
9 if (service != null ){
10 // 调用Service方法
11 service.log(LogService.LOG_INFO, " ok " );
12 // 释放Service,在此之后不应该再继续使用Service实例
13 context.ungetService(ref);
14 }
15 break ;
16 case ServiceEvent.UNREGISTERING:
17
18 break ;
19 }
20
21 }
22 }, " (objectclass=org.osgi.service.log.LogService) " );
独立于ServiceListener的访问:类似于方式一,在Listener中获取service并且保存到成员变量中,以供后续访问:
2 public void serviceChanged(ServiceEventevent){
3 switch (event.getType()){
4 case ServiceEvent.REGISTERED:
5 if (ref == null ){
6 ref = event.getServiceReference();
7 service = (LogService)context.getService(ref);// 保存实例以备后续访问
8 }
9 break ;
10 case ServiceEvent.UNREGISTERING:
11 if (ref == event.getServiceReference()){
12 context.ungetService(ref); //释放实例
13 service = null ;
14 ref = null ;
15 }
16 break ;
17 }
18
19 }
20 }, " (objectclass=org.osgi.service.log.LogService) " );
访问Service:
优点:只在Service变更时产生一次service获取开销,动态感知service的注册和注销。
缺点:在ServiceListener注册之前已经存在的Service无法监听到。需要自己维护service的获取和释放。在需要监听多个
Service实例时,使用并不方便。
三、使用ServiceTracker
ServiceTracker其实是对ServiceListener实现方式的封装,使得对service的获取更加简洁,同时也解决了不能监听到已经
存在的Service的问题(其实就是在增加ServiceListener的同时调用
BundleContext.getAllServiceReferences方法以获取现有的Service引用)。
使用ServiceTracker使得获取Service的代码更加简洁和一致,不必再考虑Service是否存在的问题,并且
ServiceTracker也提供了更加有效的监听Service的方式。
一次性访问:
2 tracker.open();
3 LogServiceservice = (LogService)tracker.getService();
4 if (service != null )service.log(LogService.LOG_INFO, " ok " );
5 // 获取多个Service
6 Object[]services = tracker.getServices();
7 // 获取Service的数量
8 int count = tracker.getTrackingCount();
9 tracker.close();
在Service注册和注销时访问:
2 @Override
3 public ObjectaddingService(ServiceReferencereference){
4 LogServiceservice = (LogService) super .addingService(reference);
5 if (service != null )service.log(LogService.LOG_INFO, " ok " );
6 return service;
7 }
8
9 @Override
10 public void removedService(ServiceReferencereference,Objectservice){
11 ((LogService)service).log(LogService.LOG_INFO, " removedService " );
12 super .removedService(reference,service);
13 }
14 };
15 tracker.open();
16
17 // 在自身lifecycle结束时关闭tracker
18 tracker.close();
有一点需要注意的是,tracker需要调用open方法才能监听到Service,另外,在bundle
stop以后,bundle内open的ServiceTracker不会自动关闭,所以一定不要忘记在bundle结束之前,关闭所有在bundle中
open的ServiceTracker。
四、使用Declarative Services
在OSGi 4以后的规范中,增加了Declarative Services方式。Declarative Services
是一个面向服务的组件模型,它制订的目的是更方便地在 OSGi
服务平台上发布、查找、绑定服务,对服务进行动态管理,如监控服务状态以及解决服务之间的复杂的依赖关系等问题。Declarative
Services 采用服务组件的延迟加载以及组件生命周期管理的方式来控制对于内存的占用以及启动的快速,很好的解决了传统的 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实现类:
2
3 import org.osgi.service.component.ComponentContext;
4 import org.osgi.service.log.LogService;
5
6 public class TestComponent{
7 public void activate(ComponentContextcontext){
8 System.out.println( " activate( " + context + " ) " );
9 }
10
11 public void deactivate(ComponentContextcontext){
12 System.out.println( " deactivate( " + context + " ) " );
13 }
14
15 public void modified(ComponentContextcontext){
16 System.out.println( " modified( " + context + " ) " );
17 }
18
19 public void bind(LogServiceservice){
20 service.log(LogService.LOG_INFO, " bind " );
21 }
22
23 public void unbind(LogServiceservice){
24 service.log(LogService.LOG_INFO, " unbind " );
25 }
26 }
2.编写component.xml:
2 < scr:component xmlns:scr ="http://www.osgi.org/xmlns/scr/v1.1.0"
3 activate ="activate" deactivate ="deactivate" modified ="modified" name ="test"
4 xsi:schemaLocation ="http://www.osgi.org/xmlns/scr/v1.1.0http://www.osgi.org/xmlns/scr/v1.1.0" >
5 < implementation class ="org.dbstar.osgi.dstest.TestComponent" />
6 < reference bind ="bind" cardinality ="1..1"
7 interface ="org.osgi.service.log.LogService" name ="LogService"
8 policy ="dynamic" unbind ="unbind" />
9 </ scr:component >
以上是有namespace的xml写法,在equinox中也支持没有namespace的写法,Eclipse中有相应的插件来提供图形化的界面来维 护component xml。以下是没有namespace的xml写法:
2 < component name ="test" >
5 < implementation class ="org.dbstar.osgi.dstest.TestComponent" />
6 < reference bind ="bind" cardinality ="1..1"
7 interface ="org.osgi.service.log.LogService" name ="LogService"
8 policy ="dynamic" unbind ="unbind" />
9 </ component >
3.将写好的xml放置到bundle根目录下的OSGI-INF下面
4.在bundle的描述文件META-INF/MANIFEST.MF中增加component相关的header:
注意xml的文件名不是绝对的,放置的目录也不是绝对的,只要在Service-Component中包含正确的路径就可以了。
一个bundle可以注册多个component,只要编写多个xml文件即可,在Service-Component中以逗号分隔。
Component的注册并不依赖Activator,所以bundle的Activator不是必须的。
另外在我的使用过程中,发现一个问题,如果xml中没有使用namespace,那么component节点上的几个callback类属性都不能定义,
例如activate属性。如果使用了namespace,那么这些属性都是可以正常使用的,不知道这算不算是bug。
关于DS规范的详细内容,可以参见:OSGi 中的 Declarative Services 规范简介
最后总结一下,综上所述的四种获取service的方法,使得service的获取越来越简单,开发者只需关注自己的逻辑,而不必纠缠于OSGi繁琐的
Service Lookup中去,同时还提供了更加方便使用的API,大家可以根据自己的需要,选择最合适的使用方式。
相关推荐
OSGi Service Platform Service Compendium 比较适合当参考书,写的很详细。。
OSGi Service Platform 4.1
OSGi 入门级教程OSGi 入门级教程OSGi 入门级教程OSGi 入门级教程中文版
总结了osgi服务发布和获取的多种方式。
OSGi Service Platform Core Specification, 比较适合当参考书,写的很详细。。
OSGi的开发和部署方式,方便部署和演示
osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍osgi介绍
In a service oriented architecture, applications consist of several cooperating services. These networks of services are often dynamic in nature, so managing dependencies is something the developer ...
OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文OSGi 中文版 中文 OSGi中文
This book is about OSGi’s role in enterprise Java and how the Spring Dynamic Modules for OSGi (Spring-DM) fulfills this role. I first learned about OSGi when the Eclipse IDE started using it in its ...
Spring OSGI 快速入门中文教程
想多前沿技术了解的朋友,一定要看哦.
Spring-OSGI 1.0 M3 中文手册
NULL 博文链接:https://tangzhifei.iteye.com/blog/1112139
1、自己开发的OSGi Web Console,适用于实现了OSGi规范的Equinox、Felix等...2、展示了如何把OSGi框架作为一个组件嵌入到现有的未基于OSGi开发的Web应用当中,在Web应用中可获取OSGi中的Service以增加应用的灵活性。
本文通过介绍传统 OSGi 应用程序及 R-OSGi 的实现方式入手,阐述了 R-OSGi 对于 OSGi 规范的实现方式。然后通过一个简单的功能实现由浅入深地讲述传统 OSGi 和 R-OSGi 上的两种不同实现,让您对实际操作加深印象。...
在felix2.0.1扩展Hibernate,使之工作于OSGI框架之中。
OSGI规范,eclipse设计是基本这个思路
OSGI 在 J2EE 环境下的应用越来越广泛,目前在 Servlet 应用中使用 OSGI 有两种方式:Servlet Container in OSGI 和 OSGI in Servlet Container. 前一种:和普通的 OSGI bundle 开发差不多,而后一种:Equinox 提供...
spring osgi 中文文档0.7