6. blueprint
1) Service Listener
这是OSGI中原生的service依赖管理机制,是最简单直接的方式,其基本原理非常简单,标准的注册/查找:
1. 被依赖的bundle通过BundleContext.registerService()方法注册服务到系统中
2. 使用依赖的bundle在start时通过BundleContext的getServiceReferences()/getService()来查找依赖的service
3. 使用依赖bundle通过BundleContext.addServiceListener()来分别注册ServiceListener
4. 在被依赖的bundle/service状态发生变化时, 使用依赖bundle通过ServiceListener的serviceChanged()得到通知并作出调整。
在这种方法中,使用依赖的Service必须进行大量的编码工作来完成对依赖的service的关系管理,需要处理琐碎细节如各个Service的运行时状态变化。为了减少工作量,OSGI设计了ServiceTracker来简化对依赖service的编码工作,即ServiceTracker将负责处理上述步骤中的2/3/4。
经过ServiceTracker优化后的Service Listener机制,还是存在一些缺点:
1. 编码量还是不小,尤其对于依赖较多的场景
2. Activator 还是太复杂了,尽管已经很努力的试图简化
对于一些业务逻辑简单的service,如果依赖的service比较多,那么Activator的逻辑和代码实现远比service本身的逻辑和实现要复杂,这违背了我们使用框架简化开发的初衷。
3. Activator对测试不利
这个是Activator的复杂性造成的,由于Activator中存在大量的依赖处理逻辑,理所当然的会增加测试的复杂性。
总结说,Service Listener 机制下,管理service依赖对于开发者来说完全是个重体力活: 很重要,经常要做,容易出现错误, 出错时不容易测试。而且,这些工作都不是service 业务逻辑的组成部分,不能带来直接收益。简言之,吃力不讨好,一不小心就搬石头砸自己的脚。
更重要的,从分工的角度上将,开发人员应该将更多的精力投入与应用的逻辑,而不是OSGI的底层实现机制。因此,从2000之后,就陆续有人开始考虑对此改进。
2) Service binder
Service binder OSGI针对这个问题的一个尝试,基本出发点非常明确:希望找到一个通用的方法来简化OSGI下的动态service依赖管理.
最初开始这个工作的是两位大牛,Richard S. Hall和Humberto,大概在2002年的时候开发完成。
看我们看Service binder是怎么做的,基本步骤为:
1. 提供一个org.apache.felix.servicebinder.GenericActivator;
现在bundle的Activator只要简单的继承GenericActivator就可以了,所有的代码实现在GenericActivator提供,减少代码的目标顺利达成。这个可以说足够简单到没有办法再简单了。
2. 通过metadata.xml 来实现service的依赖注入
3. 具体的service的实现类基本就是一个干净的POJO了
当然还是需要实现bind-method/unbind-method 两个方法,好在这个是通过metadata.xml来做映射,不是另外提供接口定义,因此勉强避开了"侵入"的问题。
Service binder 机制在减少Activator方面成效显著,但是引入的metadata.xml文件似乎又带来了新的问题,xml配置文件的可维护性个人感觉值得怀疑。用过EJB的同学都明白,EJB的部署文件有多令人烦恼。
当然Service binder 的思路非常的正确:通过引入了自动化的service依赖关系管理,简化开发,允许开发人员可以集中精力在service的实现上,而不是疲于处理依赖关系管理。
Service binder的实现似乎并没有被推广开,因为很快OSGI就在2004年的OSGI R4规范中引入了Declarative Services。因此Felix也就终止了对Service binder的后续支持。
3) Dependency Manager
继Service binder之后,Felix又提供了名为Dependency Manager 的service依赖管理方式,对比Service binder,个人感觉这个Dependency Manager 只是针对Service binder的一个改进:将metadata.xml 文件取消,由新引入的DependencyManager来实现metadata.xml 文件的功能。原来在metadata.xml 文件中的配置转变为在Activator中通过代码调用DependencyManager来实现.
Dependency Manager其实现的方式为:
1. 提供org.apache.felix.dependencymanager.DependencyActivatorBase
bundle的Activator需要继承DependencyActivatorBase,并实现DependencyActivatorBase要求的init()/destroy()方法
2. 在init()中,可以通过DependencyManager 对象来注册服务,并注明依赖。
3. 具体的Service类可以是POJO,DependencyManager 通过反射来注入依赖的service。
Felix 官方给出了一个Dependency Manager的使用示例
http://felix.apache.org/site/dependency-manager-usage.html
从示例上看,对service的依赖管理已经简化了许多。
这里还有一个05年的介绍Dependency Manager的 presentation:
http://felix.apache.org/site/presentations.data/DependencyManagement.pdf
4) Declarative Services
2004年发布的OSGi的4.0版本中,加入了Declarative Services,据说是从Service Binder进化而来。
Declarative Services的实现方式和Service Binder的确非常相似:
1. 同样是需要一个xml文件来配置
在 bundle manifest中增加Service-Component 的header
提供的功能和Service Binder很类似,配置方法也很接近。
2. 同样的提供bind/unbind 方法的配置
对于每个依赖的service,都可以在配置文件中通过指定bind/unbind 方法来处理依赖的状态变化。
此外,Declarative Services 提供两个特殊的lifecircle方法:
protected void activate(ComponentContext context)
protected void deactivate(ComponentContext context)
如果service实现类提供了这两个方法,则Declarative Services 会自动识别并调用这两个方法。注意这两个方法没有接口定义进行强约束,只是一个约定而已,估计是为了避免OSGI对service的侵入。
Declarative Services 是OSGI规范的一部分,因此Declarative Services的支持自然是各个OSGI实现都提供的。
从功能上将,Declarative Services 基本已经不错了,但是大牛们的脚步并未就此停住。
5) iPOJO
2005年,Richard 开始考虑使用字节码生成技术来进行创建组合服务的改进,另外一个牛人Peter Kriens也同样的工作并实现了一个原型。
2006年,Clement Escoffier 和 Richard 开始开发iPOJO,合并了Peter Kriens之前的工作内容,这就是iPOJO的由来。
对于iPOJO的定义,Felix的iPOJO页面有如下说明:iPOJO是一个服务器组件运行时,目标在于简化OSGI应用开发。原生支持所有的OSGI活力。给予POJO的概念,应用逻辑开发简单。非功能性的属性在运行时被注入到组件中。
同样看看Felix对iPOJO优点的说明:
1. 组件被作为POJO开发,不需要其他任何东西
2. 组件模块是可扩展的,因此可以自由的适应需要
3. 标准组件模型管理service 供应和service 依赖,所以可以要求其他任何OSGI服务来创建组合服务,
4. iPOJO管理组件实例的生命周期和环境动态
5. iPOJO提供一个强力的组合系统来创建高度动态的应用
6. iPOJO支持注解,xml或者基于Java的API来定义组件
可以看到iPOJO的功能远比之前的几个解决方案要强大,除了支持Declarative Services已经实现的功能外,还提供了强大的注解支持,而且实现了组合系统,这些对于开发大型的复杂应用时非常有用的。
Richard 在他的presentation谈到iPOJO 的设计思路:
1. Make things simple / 让事情简单
2. Follow POJO philosophy / 遵循POJO的哲学
3. Employ byte code manipulation techniques / 使用字节码操纵技术
4. Be as lazy as possible / 尽可能的偷懒
目前的iPOJO还在继续发展中,最新的一个版本iPOJO 1.6.0在2010-04-25发布。
6) blueprint
blueprint 是OSGI为了解决上述问题的最新尝试,在去年刚发布的OSGI v4.2 规范中新加入了 Blueprint Container 的规范内容。
提到blueprint 就不能不提到spring Dynamic Modules,blueprint 可以认为是Spring Dynamic Modules版本的改进和标准化。SpringDM 1.x版本实现了Spring Dynamic Modules for OSGi,在Spring Dynamic Modules被标准化为Blueprint Container 规范后,新的SpringDM 2.x 则成为Blueprint的参考实现。
blueprint 的使用实行非常类似标准的spring IOC容器,比如同样的使用xml配置文件,只是从ioc 的applictionContext xml变成了Blueprint XML。而Blueprint XML的配置方式和spring 有惊人的相似。
举例,最简单的bean:
<bean id="accountOne" class="org.apache.geronimo.osgi.Account">
<argument value="1"/>
<property name="description" value="#1 account"/>
</bean>
基本就是照搬spring IOC的方式,对于熟悉spring的开发人员来说无疑是个好消息,起码学习曲线平缓了。
由于是OSGI的标准规范,blueprint 目前的支持还是不错的,除了上面说的SpringDM外,还有Geronimo Blueprint Container 和 Apache Felix Karaf 都提供了对blueprint的支持。
总结,从上述的发展历程上看,OSGI中的service依赖关系管理方式,经历了从简单原始到逐渐成熟强大的过程,前后经历了大概10年的时间.