分享

spring+osgi 动态模型三:服务注册表(The Service Registry)

 怀旧妞妞 2011-06-23
1、输出Spring Bean作为OSGi服务
Service元素被用作将一个Bean定义为一个被输出OSGi服务,你至少需要指定将被输出的Bean和服务将对外提供的接口。
例如,下面的声明:
<service ref="beanToPublish" interface="com.xyz.MessageService"/>
输出一个名为beanToPublish的Bean为服务,这个服务具有接口com.xyz.MessageService。这个被发布的服务将会有一个名为org.springframework.osgi.bean.name的Service属性,属性值为Bean的名称(在本例中为beanToPublish)。
被Service元素定义的Bean的类型是org.osgi.framework.ServiceRegistration,它是在OSGi 服务注册表中注册输出Bean而产生的ServiceRegistration对象。给这个Bean一个ID属性,你就可以将这个ServiceRegistration对象的引用注入到任何其他Bean中,例如:
<service id="myServiceRegistration" ref="beanToPublish"
interface="com.xyz.MessageService"/>
作为输出一个命名Bean的可选方案,被输出的到Serviec注册表的Bean可以在service元素里定义为一个内部匿名Bean。典型地以beans命名空间作为顶级命名空间,如下使用方式:
<osgi:service interface="com.xyz.MessageService">
<bean class="SomeClass">
...
</bean>
</osgi:service>
如果被输出的Bean实现了org.osgi.framework.ServiceFactory接口,那么按照《OSGI Service Platform Core规范》5.6节所述,ServiceFactory约束将生效。作为实现这个接口的另一个可选方案,Spring Dynamic Modules 引入了一个新的Bean作用域:bundle作用域。当一个具有bundle作用域的Bean被输出为一个OSGi服务,那么在每个客户bundle(服务调用者)通过OSGi服务注册表获得一个该服务的引用时,都会创建一个这个Beann的实例。当调用服务的Bundle停止时,与之相关联的Bean实例会被清理
掉。要声明一个Bean具有bundle作用域仅需使用bean元素的scope属性:
<osgi:service ref="beanToBeExported" interface="com.xyz.MessageService"/>
<bean id="beanToBeExported" scope="bundle" class="com.xyz.MessageServiceImpl"/>
  •  控制由输出服务所声明的服务接口集

这里有一些选项用于在输出服务已经被注册的情况下指定服务接口(或者服务接口集)。如上所述,最简单的机制就是使用interface属性来指定一个全限定接口名。注册一个提供多个接口的服务可以使用嵌套的interfaces元素来代替interface属性:
<osgi:service ref="beanToBeExported">
<osgi:interfaces>
<value>com.xyz.MessageService</value>
<value>com.xyz.MarkerInterface</value>
</osgi:interfaces>
</osgi:service>
通过使用auto-export属性你可以不用再分析对象的类层次和接口,根本不用明确声明服务接口。
auto-export属性可选值有如下4个:
 disabled:默认选项;服务接口自动检测不会被启动,必须使用interface或interfaces元素。
 interfaces:服务将注册具有该bean所实现的所有Java接口。
 class-hierarchy:服务将注册该bean 的类及其父类。
 all-classes:服务将注册该bean的类和父类,并且注册该bean所实现的所有接口。

例如,如果想要自动注册一个bean所有它支持的接口,你需要这样声明:
<service ref="beanToBeExported" auto-export="interfaces"/>
下面给出对应的接口层次:
public interface SuperInterface {}
public interface SubInterface extends SuperInterface {}
在OSGi规范下,寻找支持SuperInterface的接口时,一个注册为支持SubInterface接口的服务不会被认为是一个匹配的结果。由于这个原因,使用interfaces元素或auto-export=”interfaces”时,这是个关于输出所有被明确注册的服务支持的接口一个不错的实践
  • 控制由输出服务所声明的属性集
如前所述,一个被输出的服务注册后会有一个服务属性org.springframework.osgi.bean.name被设置为bean的名称。其他的服务属性可以通过使用嵌套的service-properties元素来说明。service-properties元素包括一些键值对(key-value pairs),这些键值对被包在声明的服务属性之中的。key必须是一个字符串,value必须是OSGi能识别的Filter类型。关于属性值如何匹配Filter表达式请参考《OSGi Service Platform Core规范》第5.5部分。
service-properties元素必须至少嵌套包含一个Spring 的beans命名空间下的entry元素,例如:
<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface">
<service-properties>
<beans:entry key="myOtherKey" value="aStringValue"/>
<beans:entry key="aThirdKey" value-ref="beanToExposeAsProperty"/>
</service-properties>
</service>
在OSGi Configuration Administration Service中注册的属性可以输出为注册服务的属性,Spring Dynamic Modules Roadmap包含了对此支持
  • 关于depends-on属性
Spring会管理service元素所说明的明确依赖性,例如保证将要被作为服务输出的Bean在输出之前是被完整构建和配置了的。如果服务对其他组件(包括其他服务元素)具有隐含依赖性,那么被依赖的组件必须在服务被输出之前被完全地初始化。这时可选属性:depends-on可以用于表示这种依赖关系。
<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface"
depends-on="myOtherComponent"/>
  • 关于context-class-loader属性
由于有些服务使用的类库可能与context class loader有关,Spring Dynamic Modules允许你在服务的运行期完全控制context clas loader——你可以通过使用service元素的可选属性:context-class-loader来实现。
context-class-loader属性的可选值有:unmanaged(默认为此项)和service-provider。当service-provider值被指定时,Spring Dynamic Modules会确保context class loader可以看见在输出服务的bundle的class path上的所有资源。
当把context-class-loader的值设置为service-provider时,service对象会代理class loader。如果服务声明任何实际类,那么将需要CGLIB类库支持。
  • 关于ranking 属性

在用服务注册表注册一个服务时,你可能会随便指定一个服务ranking(见《OSGI Platform Core规范》5.2.5)。当一个bundle在服务注册表中寻找服务时,具有最高ranking值的那个服务将被返回。ranking的默认值为0。要为注册服务明确地指定ranking值,使用可选属性:ranking。
<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface"
ranking="9"/>
  • 服务注册和注销生命周期
在应用程序上下文(application context)第一次创建时,由service元素所定义的服务会被OSGi服务注册表注册。它会在bundle停止和应用程序上下文注销时被自动注销。
在一个服务被注销后(或注册后),对它有依赖的bundle不再是satisfied状态,如果你需要做一些操作,那么可以定义一个监听bean:使用嵌套的registration-listener元素。
注册监听器的声明必须使用ref属性指向一个顶级Bean的声明,或者声明一个内联的匿名监听bean。例如:
<service ref="beanToBeExported" interface="SomeInterface">
<registration-listener ref="myListener"--1
registration-method="serviceRegistered" --2
unregistration-method="serviceUnregistered"/>-- 2
<registration-listener
registration-method="register"> --3
<bean class="SomeListenerClass"/>-- 4
</registration-listener>
</service>
--1指向一个顶级Bean声明的监听器声明
--2指出注册和注销方法
--3声明这个监听器只有一个自定义的注册方法
--4嵌套监听bean的声明

可选属性registration-method和unregistration-method为监听bean指定在注册和注销后调用的方法。一个注册或注销回调函数必须符合如下的格式之一:
public void anyMethodName(ServiceType serviceInstance, Map serviceProperties);
public void anyMethodName(ServiceType serviceInstance, Dictionary serviceProperties);
ServiceType 可以是任何与输出服务接口兼容的类型。
register回调函数会在系统启动时初次注册服务时调用,也会在后续的服务重新注册时调用。unregister回调函数会在无论何种原因引起服务注销时调用(例如所持有的bundle停止)。
只有在一个具有兼容类型的服务将被注册或注销时,Sping-DM才会使用被声明的ServiceType 参数类型并调用registration/unregistration方法。
serviceProperties 使用一个map来存储所有注册/注销服务的属性。为了保留和OSGi规范的兼容性,如果必要,这个参数可以是被换成java.util.Dictionary.
  • 使用OsgiServiceRegistrationListener接口
如果嫌声明registration-method和unregistration-method麻烦,可以声明一个名为org.springframework.osgi.service.exporter.OsgiServiceRegistrationListener的Spring-DM规范接口。不过由于实现OsgiServiceRegistrationListener接口,你的代码变得能被Spring-DM意识到(这是有悖于POJO哲学的)。
监听器可以实现OsgiServiceRegistrationListener接口并声明自定义方法,这样Spring-DM接口方法会被优先调用,然后调用自定义方法。












    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多