模块化Java:声明式模块化 - 编程入门网
模块化Java:声明式模块化时间:2010-11-29 infoq 译:宋玮前一篇文章,《模块化Java: 动态模块化》描述了如何通过使用服务 (service)给应用程序带来动态模块化特性。它们是通过输出的一个(或多个 )可以在运行时被动态发现的接口而实现的。尽管这种方式使得client和server 完全解耦,但是又带来一个如何(何时)启动服务的问题。 启动顺序 在彻头彻尾的动态系统里,服务不仅可以在系统运行的时候装卸,还可以以 不同的顺序启动。有时,这是个大问题:无论A和B的启动顺序如何,在系统达到 就绪状态并准备好接收事件之前,如果没有事件(或线程)出现,那么哪个服务 先启动都无大碍。 可是,有很多情况都不符合这一简单假设。经典的例子就是logging: 通常, 服务在启动和做其他操作的时候,就要连接并开始写日志了。如果日志服务此时 还不可用,那会有什么后果? 假定服务在运行时能够动态装卸,client应该能够应对服务不存在时的情况 。在这种情况下,它也许能聪明地转移到另一种机制(如输出到标准输出),或 者处于阻塞状态等待服务可用(对logging系统来说不是好的答案)。可是,让 服务启动之前就可用是不切实际的。 启动级别 OSGi提供了一种机制来控制bundle启动时的顺序,即使用启动级别(start levels)。这一概念是基于UNIX运行级别的概念:系统以级别1启动,然后单调 递增,直到达到目标启动级别。每个OSGi容器都提供了不同的默认目标级别: Equinox默认值是6;而Felix是1。 启动级别可被用来创建bundle间的启动顺序,让关键bundle服务(比如 logging)的启动级别比那些需要用它的bundle更低。可是因为可 用的启动级别 值是有限的,而且安装程序倾向于选择单一数字作为启动级别,因此它并不能确 保你仅通过启动顺序就能解决问题。 另一点值得注意的是,具有相同启动级别的bundle是各自独立启动的(可能 并行),因此,如果你有一个与log服务具有相同启动级别的bundle,谁也不能 保证log服务能够在需要的时候已经就绪。换句话说,启动级别可以解决大部分 问题,但不能解决所有问题。 声明式服务 解决这一问题的一个方案是OSGi的声明式服务(以下称为DS——declarative services)。用这一方法,各个组件是由外部bundle将他们组织在一起并决定他 们什么时候可用。声明式服务是通过在一个XML配置文件组织在一起的,文件中 描述了需要(消费)或提供什么服务。 在上篇文章最后一个例子中,我们使用ServiceTracker去获得服务,如果必 要则需等待服务可用。如果我们把创建shorten命令延迟到shortening服务可用 之后会很有用。 DS定义了一个组件(component)概念,其是比bundle更细粒度的概念,但是 比服务的概念粒度更大一些(因为一个组件可以消费/提供多个服务)。每个组 件都有一个名字,对应一个Java类,并可以通过调用该类的方法使其激活或失效 。与OSGi Java API不同,DS允许用纯Java POJO来开发组件,根本不需要从程序 上依赖OSGi。其附带的好处是让DS更加易于测试和模拟(test/mock)。 为了说明这一方法,我们将继续使用前面的例子。我们需要两个组件:一个 是shortening服务本身,另一个是调用它的ShortenComand。 第一项任务是用DS配置并注册shorten服务。我们可以让DS在服务启动时注册 它,而不是通过Bundle-Activator注册该服务。 那么DS怎么知道要激活并连接谁呢?我们需要给Bundle的Manifest头增加一 个条目,其指示了一个(或多个)XML组件定义文件。
这个 OSGI-INF/shorten-tinyurl.xml组件定义文件内容如下:
|
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |