Jeff 在 EclipseCon 2006 那篇介绍 Equinox 的 PPT 中提到的 Declarative Services( 文中全部采用 DS 简称 ) 的用法让人极度被吸引,但同时又产生怀疑,想起以前自己看过 DS 好像不是这样的,没这么强,便再次翻阅了 OSGI R4 中的 DS 的章节,以验证 Jeff 的说法, ^_^ ,仔细看过 DS 章节后,确实为 Declarative Services 的强大而感到高兴, DS 是一个面向服务的组件模型,从组件模型层次上去看,它超越了传统的组件模型,在组件模型描述的完备性上有了很大的进步,例如在组件服务的依赖上、组件服务的延迟加载上、组件服务的多样性控制上、组件服务的配置上以及组件服务的生命周期管理上,不过 DS 只能在 OSGI 容器中使用,这尽管看上去可能是个弱点,但作为 OSGI 规范中的一部分,这无可厚非,其思想值得很多目前 Component Model 的开源框架值得思考和学习,如感兴趣,请阅读 OSGI R4 中 DS 章节。
简介
DS 制定的目的是为了提供发布 / 查找 / 绑定服务的模型,作为 OSGI 中的规范,它的关注和 OSGI 其他的规范一样,都在于对于内存的占用、代码的大小、启动的快速以及使用的简易方面, ^_^ ,和一般做 java 的开源框架的那些可能不同,这也给我们带来了不同的视角,可以看到 DS 是怎么去考虑这些方面的,在内存的占用上, DS 采用提供组件的延迟装载以及强大的组件生命周期管理的方式来控制对于内存的占用以及启动的快速,使用的简易方面 DS 采用一个简单的 xml 描述来实现,加上它对于 Component 并没有太多的要求,所以用起来还是比较简单的。
Component
及其
Lifecycle
DS 作为 Service-Oriented Component Model ,双重的体现出了 Component 、 Service 的概念 ( 在 DS 中其实它的准确命名是 Service Component) ,一定程度上解决了以前经常可见的所谓的 Component-Oriented 以及 Service-Oriented 的混淆概念,在 DS 中采用的为定义 Component 的方式,每个 Component 可以暴露出多个服务,同时也可依赖于多个服务, DS 中有三种类型的 Component ,分别为 Immediate 、 Delayed 以及 Factory ,从字面上就可以理解了,在介绍这三种类型的 Component 之前先来讲讲如何在 DS 中定义 Component 以及 Component Satisfied 的含义。
在 DS 中定义 Component 采用的为通过 xml 描述的方式,在 DS 章节中有关于 Component xml 描述的详细介绍,具体可以参见该章节,此 xml 描述非常的简单, ^_^
Component Satisfied 的含义非常关键,在 DS 中 Component 的生命周期和这个有着密切的关系,象 Component 的激活就要求 Component Satisfied ,而当 Component 在运行过程中一旦出现 Unsatisfied 的现象 Component 就会被自动的注销,那么在 DS 中 Component Satisfied 的概念到底是指什么呢? Component Satisfied 可以这么理解,它是 Component 激活的前置条件,它主要由两点来决定是否为 Satisfied :
1、 Component 是 Enabled ;
2、 Component 的配置可被引用和解析、 Component 中引用的 Service 同样也是 Satisfied 的,同时引用的 Service 至少有一个是处于可用状态的,或者引用的 Service 中配置了可为 0 个可用状态 service 。
再回到三种类型的 Component ,分别看看他们的生命周期是怎么样的:
三种类型的 Component 的启动都依赖于 Component 处于 Satisfied 的状态下:
Bundle 启动时 DS 装载相应的配置文件 ( 通过在 mainfest.mf 中指定 Service-Component: 配置文件 ) ,解析配置文件,合并其中的组件的配置部分,获取引用的 Service ,如上面的几个步骤全部通过,那么 DS 就认为这个组件是 Satisfied 的。
1、 Immediate
对于 Immediate Component , DS 会立刻激活这个 Component 。
在这个 Component 的配置文件被改动、配置信息文件 (properties 文件 ) 被改动以及所引用的 Service 被改动的情况下, DS 都会重新装载并激活这个 Component ,同时对于引用了这个 Component 中 Service 的 Component 也会做同样的动作。
2、 Delayed
对于 Delayed Component , DS 会根据配置文件中的 Service 的配置,注册 Service 的信息,但此时不会激活这个 Component 。
直到这个 Component 被请求的时候 DS 才会去激活这个 Component ,相应的设置引用的 Service 。
在这个 Component 引用的 Service 发生改变的情况下, DS 不会重新装载这个 Component ,而会采用调用配置中设置的 bind 、 unbind 方法来重新设置引用的 Service 。
3、 Factory
Factory Component 和 Immediate Component 基本相同,不过它在激活后注册的只是一个 ComponentFactory 服务,只有在调用 ComponentFactory 的 newInstance 后才会激活里面的各个组件。
这三种类型的组件中无疑 Delayed Component 是最需要的,为系统的动态性带来了很大的好处,同时也节省了内存的占用。
组件的生命周期受 bundle 生命周期影响,当 bundle 停止时 bundle 中所有组件也就停止。
Service
的发布
/
查找
/
绑定
既然是
Service-Oriented
,最为关心的当然是
Component
中
Service
的发布
/
查找
/
绑定,分别来看看:
u
Service
的发布
对于
Component
中
Service
的发布,在
DS
中非常简单就可以做到了,只需要在
Component
的
xml
中编写如下一段:
<service>
<provide inter>
</service>
这样外部的
DS
就可以引用这个
interface
的
service
了,可以看到,在这个
xml
的属性里采用的是
interface
的声明方式,尽管其实这个
interface
里也是允许填入实际实现服务接口的类名的,但不鼓励这么做。
可以看到
Service
的发布非常的简单,只要
Component
实现了相应的
Service
的接口即可。
u
Service
的查找
DS
中也提供类似
jndi lookup
那样的方式,在
Component
中可以通过定义
activate(ComponentContext context)
这样的方法来获得
ComponentContext
,通过
ComponentContext
就可以获取到在
Component
配置文件里定义的引用的
Service
了。
配置文件类似这样:
<reference name=”LOG” inter>
代码类似这样:
public void activate(ComponentContext context){
LogService log=(LogService)context.locateService(“LOG”);
}
^_^
,很简单的一种方式。
u
Service
的绑定
DS
中提供直接绑定
service
的方法,按照
DI
的观点来说其实就是注入
service
的支持,
DS
提供的是类似
setter
注入的方式,只是更加的强,
^_^
,因为
DS
会根据引用的
Service
的状态来相应的调用这个
setter
注入,在
DS
中要采用这种方式也很简单。
配置文件类似这样:
<reference name=”LOG” inter bind=”setLog” unbind=”unsetLog”/>
代码类似这样:
public void setLog(LogService log){
this.log=log;
}
public void unsetLog(){
this.log=null;
}
可以看到这和目前流行的
setter DI
方式完全相同,而且更强,
^_^
,
DS
帮忙监听了所引用的
Service
的生命周期状态,会根据
Service
的生命周期状态相应的调用
unbind
方法,连监听器都省了,
^_^
,后面再介绍下
Service bind
的
static reference
和
dynamic reference
的方式,那时就会发现它更强了,呵呵
这样看下来,可以看出
DS
要实现现在的
DI
方式同样完全是可以的,而且有更为强大的支持,在
DS
的情况下也是可以采用纯
POJO
方式的
Component
的
(
因为象上面提到的
activate
那个方法是可以不写的
)
,爽,对于以前用过
OSGI
中通过
ServiceRegistry
以及
ServiceReference
来发布
/
查找服务的同学们来说就会更有体会了,
^_^
更多
DS
提供的不仅仅是上面所说的那些,还有很多非常强的功能,例如:
u
Component
配置
在
Spring
的
bean
的配置文件中可以引用外部的配置文件的配置信息,在
DS
中同样可以,而且更为简单,在
DS
中只需要在
Component
的
xml
描述文件中采用类如
property
来直接指定属性或采用
properties
来指定引用外部的配置文件即可,而且这个配置文件的属性在
Component
中可以通过
ComponentContext
来获取。
u
Service
的
Static
、
Dynamic
引用
对于
Component
中引用的
Service
,
DS
可以采用两种策略,一种是
static
,另外一种是
dynamic
,默认情况下是
static
的方式,在采用
static
方式的情况下,如引用的
service
发生了变化,那么整个
Component
都会重新装载并激活,而在
dynamic
方式的情况下,只会重新调用其中的
bind
、
unbind
方法。
在
DS
中通过在
reference
元素中增加
policy
的属性来控制采用
static
或
dynamic
方式。
u
引用的
Service
的过滤
这个的含义其实在目前其他的
Component Model
中可能较少碰到,在
DS
中是支持一个
Service Interface
由多个
Component
实现并暴露多个实现的
service
的,在这种情况下可能希望只引用某种
service
的实现,那么在
DS
中可以通过在
reference
元素中增加
target
属性来声明对于引用的
service
的过滤。
u
Cardinality
这个词不知道该怎么翻译好,就没翻译了,它里面指的主要是两点,一个是多样性,一个是引用的
service
的数量的控制,这点挺强的,
^_^..
可以通过指定
optionally
属性值来决定引用的
service
的数目为
0
到多、
1
个、
1
到多或其他情况。
要将
Component
进行部署非常简单,在编写了上面的
Component
的
xml
描述文件后,只需要在现在的
Bundle
中增加
Service-Component
这个属性即可完成部署工作。
作为
OSGI
规范大家庭中的一个小部分,其可以充分利用
OSGI
规范中其他的
Service
来增强相应的功能,如
Security Service
来增强安全性等。
对于传统的
Component Model
来说,
DS
在
Component
的
Service
的发布
/
查找
/
绑定方面的机制、
Component
的生命周期管理机制、引用的
Service
的管理机制上都值得学习,
^_^
目前
DS implemention
还没有正式发布,按照
roadmap
来看的话要等到
eclipse 3.2
正式版发布后才能
release
,还得等等,
^_^
,先去
CVS
上下目前的
implemention
来用用,看看目前的
DS implemention
有多强了
…