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 interface=”net.bloajva.DemoService”/>
</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” interface=”org.osgi.service.log.LogService”/>
代码类似这样:
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” interface=”org.osgi.service.log.LogService” 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
有多强了
…