领域修炼之路

通过OSGi Bundle进行资源隔离

简述

随着OSGi越来越被大家所熟知,基于OSGi的开发成为一种趋势。在OSGi中,两个核心元素是Bundle和Service,本文仅涉及Bundle,Service不在讨论范围之内。

OSGi中的Bundle通常被看做是一个细粒度的功能模块,为整个基于OSGi的系统提供某项功能。但是,Bundle的资源组织特性,使其可以不仅仅作为一个功能模块,也可以作为资源组织模块来应用。Bundle的资源组织特性是Bundle的功能特性的基础支撑。Bundle的资源组织特性可以在某些特定应用中得到充分的利用,本文就Bundle的资源组织特性在一类特定需求中的应用及各种实现方案做了详细的阐述,并提供了一种另类的实现。

为了更好的区分Bundle的功能特性和资源组织特性,我们在下面的讨论中将这两种不同侧重点的Bundle分别称之为“功能Bundle”和“资源Bundle”。

OSGi Bundle的特点

OSGi框架为基于Java的系统开发提供了灵活的动态模块化支持。OSGi的模块层(Module Layer)为Java组件模块化提供了一种标准的解决方案。在OSGi中, Bundle部署成为一个Java Archive(JAR)压缩(ZIP格式)文件,该文件包含的内容有:提供某些功能的资源文件,如Java类文件,帮助文件,HTML文件,配置文件等等;一个元数据文件,用于描述该压缩文件的信息及其内部所包含的资源,OSGi框架使用这些元数据信息来安装并激活Bundle。

在OSGi中,每一个Bundle具有自己独有的 ClassSpace(详细信息参考OSGi规范)边界,Bundle间通过导出(Export)内部Java类,导入(Import)其他Bundle导出的Java类,来构造自己的ClassSpace边界。

Bundle之间也可以设定依赖关系,一个Bundle可以通过元数据 Require-Bundle 头来描述一个Bundle所依赖的其他Bundle列表。

OSGi中的Bundle接口提供了方法用于获取Bundle内部存储的资源,加载Bundle内部的Java类,通过实现BundleActivator接口获取BundeContext与其他Bunde进行交互。

资源Bundle的应用需求

在现实环境中,应用系统为了提高适应性和可扩展性,系统的设计开发越来越依赖于配置而不是硬编码。不同的系统,根据各自特点的不同,对于配置的依赖程度是不同的。下面以企业应用集成中的EAI中间件实现为例说明配置资源对于系统的重要性。

举例来说,存在待集成的两个系统,一个系统提供数据库访问接口,另一个系统提供WebService接口。为了实现这两个系统的集成,可以选择如下方式:

  1. 为此次集成需求做特定开发。这是最差的一种实现方式。

  2. 为数据库访问和WebService访问接口开发尽可能通用的模块,根据此次需求的差异性,对这些模块做适当定制开发。这是实际应用中最常见的实现方式。

  3. 开发通用的数据库访问接口和WebService访问接口模块,通过配置来处理实际需求的差异性。此种方式最为完美,但对模块的设计具有更高的要求。

中间件系统为了能够集成各种各样的应用系统,必须采用上述第三种方式,因此,中间件的实现高度依赖配置。

系统集成的复杂度依赖与系统业务的复杂度,简单的系统集成可能仅需要一种或几种配置即可满足需求;但是对于复杂的业务系统集成需求,可能存在几十中甚至上百种配置。很明显的一个示例是两个应用系统之间需要传输几十种业务报文,随着业务的不断发展变化,业务报文的内容和数量在随时产生变化。采用上述三种方式中的前两种方案来解决此种需求就要面临不断地进行维护和开发的成本,而采用第三种方案则可以避免开发而仅仅维护配置,维护成本将大大降低。

下面我们来看一下资源Bundle在上述需求中的充当配置资源的优势:

  • 集中的资源配置控制。
    可以将各种配置分散到各个资源Bundle中,通过OSGi框架统一管理这些资源Bundle。

  • 资源配置的生命周期控制。
    资源Bundle在OSGi中具有生命周期,可以控制资源Bundle的安装,卸载。

  • 资源配置的状态处理。
    资源Bundle在OSGi中的状态变化会产生事件,通过监听这些事件,可以对资源Bundle的各种状态进行内部处理。如可以捕获资源Bundle的安装事件对Bundle中的资源文件进行有效性检查。

  • 资源配置可以包含程序代码。
    系统在处理某种资源配置时可能需要为此种配置提供特定的程序扩展实现,使用资源Bundle就可以将扩展代码与资源配置打包在一起,进行统一管理。实际应用中最常见的例子是Java实体Bean。

  • 资源Bundle的类空间(ClassSpace)隔离。
    现实应用中,不同的用户可能共同使用同一个系统,并在此系统中设计自己的资源配置,如果用户的资源配置中可以包含Java类代码,则利用资源Bundle可以避免用户间的类代码冲突。

  • 资源Bundle之间的依赖关系。
    OSGi Bundle之间可以设定依赖关系,作为资源Bundle也可以设定对其他资源Bundle的依赖,这种依赖限定可以为资源配置提供额外的可靠性约束。

资源Bundle在不同的应用中所体现的优势可能不同,大家可以充分结合实际需求来利用。

##资源Bundle的应用方案

###功能Bundle即资源Bundle

前述说过,资源Bundle是功能Bundle的基础,功能Bundle也是一个资源Bundle,如果该功能Bundle的配置资源比较固定并且简单,可以直接将配置资源放置于该Bundle内。此种方案在基于OSGi开发的系统中来的最为直接。

###在OSGI中资源Bundle与功能Bundle分离

某些功能Bundle可能需要多种资源配置,而各种资源配置可能具有自己的变更周期,为了不影响其他配置的使用,可以将这些配置拆分成独立的资源Bundle,由功能Bundle根据需要查找使用。

为了区分功能Bundle和资源Bundle,可以通过定制OSGi元数据头信息来实现。如在MANIFEST.MF文件中添加 Bundle-Type: Resource 的自定义属性来标明该Bundle是资源Bundle。并利用其他定制属性来标明该资源Bundle的具体业务信息。

Resource Bundle1

如上图所示,功能Bundle和资源Bundle处于同一个OSGi框架之内。功能Bundle通过BundleContext可以查找资源Bundle并获取资源Bundle内的资源。这种方式的前提是系统必须基于OSGi框架开发。

传统应用利用OSGi作为资源配置中心

在传统应用中利用OSGi来作为资源配置中心,就需要将OSGi框架内嵌到自己的应用系统中。透过内嵌的OSGi框架获取该框架所管理的所有资源Bundle。目前,在各种OSGi的开源实现中,Felix为内嵌应用提供了很好的支持。

关于如何内嵌Felix,请参考Felix项目网站的相关文档。

Resource Bundle1

在OSGi环境中利用OSGi作为资源配置中心

如前所述,资源Bundle和功能Bundle可以在同一个OSGi框架中共存,各个功能Bundle透过BundleContext控制和获取所需的资源Bundle中的资源,但是,此种应用方案存在明显的弊端,资源Bundle和功能Bundle混杂在一起难于控制,随着资源Bundle数量的增多,系统将会越来越复杂。

理想的解决方式就是将资源Bundle和功能Bundle分离,为资源Bundle提供单独的OSGi环境。因此,可以将OSGi框架实现作为一个独立的功能Bundle(反转OSGi,非System Bundle)作为资源Bundle的控制中心和入口点。如下图所示。

Resource Bundle1

结论

OSGi为Java模块化系统开发提供了一种强大的解决方案。OSGi框架中所包含的各种设计思想可具有很高的利用价值。在OSGi环境中利用OSGi作为资源配置中心是一个很有意思的构想,在此构想的实现中过程中我们会面临一些非常有挑战的问题。

chrisrc wechat
更多信息请订阅我的微信订阅号