APP下载

基于OSGi的类资源冲突机理与消解方法

2016-07-04马娜

电脑知识与技术 2016年15期

马娜

摘要:作为面向服务计算泛型的一种重要实现手段,OSGi为构建具有模块化、“即插即用”、可动态持续演化的软件系统,提供了一个强大的通用化平台和规范支持。针对层次化类装载器代理体系下,OSGi服务平台中类资源装载冲突问题,从基于Java平台的OSGi类装载体系出发,对造成类资源冲突的基本原理进行分析,给出消解冲突的基本原则。提出了遵循该原则的基于第三方共享Bundle、及静态和动态资源冲突检测的冲突消解方法,并给出了方法的具体实现方式。

关键词:Java类装载器;OSGi;类资源冲突;冲突消解方法

中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2016)15-0074-04

随着计算机软件与互联网技术的快速发展,软件计算泛型大致经历了从面向对象、面向构件到面向服务计算(SOC)泛型的转变。SOC是一种以服务为基本元素,进行软件应用和解决方案设计、实现的软件计算范型,反映了自治、异构的互联网环境中软件的构件化趋势[1]。近年来,得到广泛关注的云计算技术也是以服务为核心的一种新的应用与商业模式[2]。

OSGi是具有开放、通用软件架构的服务平台规范,为服务提供者、开发者等提供一种协作完成服务开发、部署与管理的模式[3],是SOC泛型的一种重要实现手段[4]。OSGi支持基于可复用服务插件的可插拔软件系统的构建,能以插件为粒度实现软件行为的动态改变,通过插件间隔离保障系统运行时的稳定性与可靠性。目前,OSGi已得到众多企业、厂商、开源组织的支持,如Apache、Eclipse、Spring等,并已成为事实上的Java模块化公认、通用标准[5]。目前,OSGi技术已在智能家庭网络[6],嵌入式软件[7,8],传感器网络[9]等领域得到关注与初步应用。

OSGi的类装载机制,提供了灵活、安全、独立的类装载能力,但常常导致潜在的类资源的装载冲突问题,进而提高Bundle开发、第三方Bundle集成的复杂性,增加系统实施的成本,甚至限制OSGi技术在大型、专业软件公司之外的普适性推广与应用能力。因此,理解和掌握OSGi服务平台技术体系下类资源冲突机理,并采用适合的消解方法,已成为该领域基础理论研究与发展,及工程实施与应用推广所面临的重要基础性问题之一。

1 相关技术

OSGi服务平台中Bundle相关的类资源装载,依赖于Java平台的虚拟机的实现(如无特殊说明,下文提及虚拟机均指代Java虚拟机)。

虚拟机的主要任务是装载Class文件,生产字节码,并将字节码交由运行时引擎执行[10]。类装载器是虚拟机一个重要的组件,负责完成从应用程序和Java API中装载Class文件,Java API实际上是Java平台提供的系统类资源。同一个虚拟机中可以存在多个类装载器的实例,形成灵活的虚拟机运行时类装载器体系,如图1所示:

不同类型的类装载器实例,构成了一个运行时类装载的代理体系,形成类装载器的父/子层次关系。当虚拟机需装载某一Class文件时,会从应用类装载器(如存在)开始,逐层代理给系统类装载器、扩展类装载器和启动类装载器。子装载器会为其父装载器提供一个类装载机会,以便装载任何给定的类,并且只有父装载器失败时,其子装载器才会进行类的装载[11]。上述类装载器在装载类时,实际上是搜索不同的Class文件的存放路径。例如:扩展类装载器搜索Java平台的ext目录,而应用类装载器搜索自定义的类存放路径,可以是本地文件系统,也可以是网络文件目录。

理解装载器体系的代理关系,以及不同类型装载器的Class文件搜索方式,是理解OSGi技术体系下类资源冲突的基础,本文将在第2节对这种冲突的成因和机理进行分析。

2 冲突机理分析

虚拟机层次化、可扩展的代理装载体系,能控制不同来源的Class文件中装载类资源之间的相互影响,这种特性是OSGi通过类装载机制实现不同Bundle间运行时隔离的技术基础。正因为如此,OSGi规范的实现(Felix、Equinox)绑定为Java平台,而非诸如.NET、C++等语言平台。

Bundle是OSGi实现Java模块化的最基本单元,Bundle的类资源可以从多种途径获得,包括:Java平台的系统类资源,通过import、require和fragment方式来自其他Bundle的类资源,以及Bundle本地私有的类资源[3]。每个Bundle均拥有一独立的类装载器负责本地类资源的装载,并共享Java虚拟机、OSGi容器提供的全局性类装载器。为了保证模块的隔离性,Bundle间通过导出和导入包的方式,隐藏内部实现细节,并通过服务接口调用其他Bundle提供的服务。这种机制下,Bundle间的接口调用是一种典型的客户/服务器关系。基于Java平台的Bundle间类资源的典型关系如图2所示:

Bundle A可使用本地类资源,也可通过导入关系,使用Bundle B的本地类资源;可通过系统Bundle获得Java平台提供的类资源。OSGi定义了一套满足模块化隔离性的类装载机制,因篇幅所限本文不再详述,可参加文献[3]。本文以Apache Felix OSGi实现为例,根据图2分析OSGi技术体系下类资源的装载过程,如图3所示。

Bundle A定义和其本地路径的类由Bundle A的私有类装载器负责装载;以Java.*开头的包中的类由Felix框架的启动类装载器装载(与虚拟机的启动根装载器不同);由Bundle B导出,Bundle A导入的类,则由Bundle B的类装载器负责装载;其他诸如虚拟机的扩展和系统路径下的类,则通过Felix代理给虚拟机的类装载器,按图1所示虚拟机代理装载器机制装载。

上述基于虚拟机的类装载体系中,不同的类或相同的类均可能被不同类型的类装载器装载,或者不同应用类装载实例装载。通过类装载器,构建了Java平台运行时的多个命名空间,这种命名空间由类装载器、类的包名和类的名称进行唯一标识。因此,来自不同搜索路径下具有相同包名和类名的类,由于其命名空间的不同,将被虚拟机以不同的类定义对待。这种情况下,Bundle间传递不同命名空间中的同名类,就会出现类资源冲突问题。此外,OSGi对Bundle及其内部Java包的版本信息进行严格限定,允许Bundle的不同版本同时存在于虚拟机运行时环境,这也可能引发类资源冲突,将在第3节消解方法中说明版本原因造成的冲突问题及消解方法。

3 消解方法

OSGi技术体系下的类资源冲突问题,为采用OSGi服务平台进行工程实施与应用带来了大量的潜在风险与问题。运行时类资源冲突问题的引入原因多种多样,本文以图4(a)和(b)所示Bundle间关系为例,分析运行时类资源冲突问题引入的典型场景。

图4(a)中,Bundle A调用Bundle B提供的Invoke服务方法,该服务需传入类型为Class C的参数实例,Bundle A和Bundle B均将Class C作为本地类资源使用。虚拟机运行时类资源装载时,Bundle A和Bundle B使用各自的私有类装载器装载Class C。由Bundle A创建并传递给Invoke服务方法的Class C实例,与Bundle B初始化Invoke服务时的Class C的类定义,隶属于不同类装载器命名空间。在Invoke服务方法调用时,将会出现运行时类资源装载冲突问题。

图4(b)中,Bundle A在本地有subClass和Class para两个类资源,且前者依赖于后者。subClass是Bundle B本地的parentClass的子类,Bundle A通过导入关系,引用parentClass。Bundle B的parentClass类依赖于Class para类,但Bundle B本地没有该类资源,而是通过导入Bundle C的本地类资源,获得Class para类的引用。当Bundle A装载subClass时会委托Bundle B加载其父类parentClass,而subClass和parentClass所依赖的Class para类资源,分别由Bundle A和Bundle C的私有类装载器进行装载。此时,虚拟机在运行时进行subClass类的连接过程中,会产生类资源装载冲突问题。

根据对上述典型场景及第二节冲突机理分析结果可知,导致OSGi技术体系下类资源冲突的根本原因是,不同Bundle间类由于参数传递、运行时链接等情况下,相同类资源被不同类装载器多次装载。可推导出消除这种冲突的基本原则是,限定Bundle间由某一确定的类装载器从确定的搜索路径下装载“共享”类资源,可以是虚拟机提供的类装载器、OSGi提供的启动类装载器或某Bundle私有的类装载器。为了满足该冲突消解原则,总体而言可以有以下三种消解方法:

1) 对OSGi实现进行修订,已得到OSGi系统平台的支持。可适应性修改OSGi实现的类装载过程,当出现冲突时,由平台自身选择某确定的类装载器进行装载。这种修订必将破坏OSGi的规范性和通用性,无法保证对所有潜在类装载冲突消解的覆盖性,并且实现的复杂性和成本过高。

2) 将共享类资源统一归并到Java平台,即将其驻存在虚拟机自身可搜索到的默认路径,例如Windows操作系统下CLASSPATH配置的系统路径或者jre/lib/ext的扩展路径。需注意的是,一旦共享类资源放入扩展路径,如类需调用系统类或扩展类,扩展类装载器将无法装载。然而,虚拟机是相对底层的系统软件,这种方式某种程度上破坏了Java平台自身的通用性。

3) 设计时引入独立的第三方共享Bundle(可以是普通Bundle、Fragment Bundle、或Extension Bundle,相关细节可参考文献[3]),将需共享的类资源统一装配到共享Bundle,并导出需共享的类资源,依赖于共享类资源的Bundle均通过共享Bundle导入。采取基于Bundle装箱单(即MANIFEST.MF文件)[3]的静态冲突检测,及运行时动态冲突检测与报警机制,规避设计时和运行时潜在的类资源冲突问题。该方法,不依赖虚拟机或OSGi平台的实现,完全取决于设计时对Bundle间关系的规划;对虚拟机或OSGi平台的实现不造成破坏,具有较好的灵活性,无论是自研还是集成第三方提供的Bundle,均适用于此方法。

3.1 类资源冲突消解架构

通过对以上3种可能的类资源冲突消解方法的分析,且考虑到实现复杂性、成本及Bundle版本等方面的因素,本文建议采用方法3)。根据方法3),具体的类资源装载冲突消解方式如图5所示:

第三方共享Bundle的引入,实际上是将多个Bundle共享类资源,委托给共享Bundle进行管理和装载,将共享类资源存放在共享Bundle的本地路径,由其私有类装载器负责装载共享类资源。这种方式,共享类资源的运行时装载,将明确由共享Bundle私有类装载器从其本地路径进行装载,从而避免多装载器重复装载时出现的类资源冲突问题。

3.2 静态资源冲突检测

静态冲突检测工具依赖于装箱单文件,在设计时分析Bundle间的依赖关系,并对潜在的类资源版本引用冲突进行检查。装箱单是OSGi服务平台的重要特征,可记录Bundle基本配置信息及类资源引用信息,其具体功能可参见文献[3]。

通过分析各个Bundle的装箱单中的Import-Package,Require-Package,Fragment-Host、Bundle-ClassPath等配置信息,静态冲突检测工具可以在设计时分析Bundle间静态引用关系;进一步地,根据OSGi装载体系与过程,构建各个Bundle间类装载器代理关系,形成类装载器代理网络结构图。在此基础上,可同时分析引用关系中版本信息可能引发的潜在类资源冲突问题。以图5为例,Bundle A和B分别从Shared Bundle导入版本为1.0和1.1的Class para类资源,此时如果Bundle A和B存在依赖关系,则静态冲突检测工具会对其进行预警反馈,以对软件系统设计优化进行指导,并消除潜在类资源冲突。

3.3 动态资源冲突检测

OSGi服务平台的核心优势之一是模块化的“即插即用”,保障软件系统运行时的行为动态演化能力。当在运行时动态添加、替换Bundle时,需要一种运行时类资源冲突检测的手段,为此,本文提供一种如图5所示的动态冲突检测方法。

该方法依赖于OSGiSystem Bundle提供的基于系统事件发布器的系统事件订阅/发布机制。System Bundle启动时会主导其他Bundle的安装及其类资源装载的过程(如Felix System Bundle的初始化与启动方法),并维护其运行时生命周期状态,例如:Bundle的安装、解析、启动、卸载等。当某Bundle状态发生改变时,会通过系统事件发布器对外发布相应的系统事件。

基于这种事件机制,本文实现一个用于监听系统事件的动态冲突检测Bundle,简称DCBundle,用于完成OSGi服务平台运行时出现添加或替换Bundle情况下的类资源冲突的检测。DCBundle的主要工作过程如下:

1) 在被System Bundle启动时将自身注册到系统事件发布器,成为系统事件的监听者,并将自身设定为非工作状态;

2) 整个OSGi平台启动完成后,接收一个外部命令,将自身设定为工作状态;

3) 监听、捕获系统事件发布器的Bundle安装事件,将新安装的Bundle信息记录在检测队列;

4) 监听、捕获系统事件器发布的Bundle解析事件,获取其Revision和BundleWiring对象(可认为是Bundle装箱单文件的运行时内存结构),并进行运行时类资源冲突检测;

5) 如存在类资源冲突,则通知动态冲突监视工具,否则将新安装的Bundle从检测队列中移除,并继续监听系统事件。

4应用与分析

本文在Eclipse3.6集成开发环境,开发实现了基于Felix和Equinox两套OSGi服务平台的静态冲突检测工具、动态冲突检测Bundle及动态冲突监视工具,并将其应用于北京卫星信息工程研究所自主研发的××云计算软件平台(以下简称云平台)的类资源冲突检测。该平台的软件架构如图6所示。

IaaS和PaaS层共提供了7类基础软件服务,这些软件服务均采用OSGi标准,以Bundle为基本模块实现。其中,某些服务基于开源项目Hadoop1.0版本,进行完善和适应性修改。自研部分也应用某些第三方Java包或Bundle实现,例如SL4J、Spring DM等。

目前,整个平台的基础服务涉及1200多个Bundle的调试与集成。Bundle间存在类资源依赖关系、本地类资源冲突与版本一致性等较为复杂的关系。由于动态冲突检测时涉及的Bundle数目一般较少,本文重点对静态冲突检测进行测试,在Intel Core TM处理器E7500,双核2.93GHz,内存1.96GB的台式机上进行实验。本文对每个实验重复10次,得到其平均静态冲突检测时间。结果如表1所示:

表1中,随Bundle规模的增大,检测时间也会增多,但所用时间并非线性增加。除Bundle规模外,Bundle间的依赖关系、对Java 平台提供的类资源的依赖程度等,也是影响静态冲突检测时间的因素。在此,本文并未对其他因素的影响进行分类和试验分析,将在后续工作中进行深入研究与分析。

从实验结果看,本文提供的静态冲突检测工具,与SourceCounter、Findbugs、CheckStyle等用于代码量统计及静态分析工具的时间效率相当,可做为项目与工程实施中的应用工具使用。

5总结

OSGi特有的层次化类装载器代理体系,及私有类装载机制的实现,是其重要的基础性核心技术之一。这种内核机制所引发的潜在类资源装载冲突问题,限制了其在大型、专业软件公司之外的普适性推广与应用能力。本文从Java平台类装载体系出发,分析引发OSGi技术体系下类资源装载冲突的原因与机理,并给出实现冲突消解的基本原则。在此基础上,分析了三种可能的冲突消解方法,对基于第三方共享Bundle、及静态和动态资源冲突检测的冲突消解方法进行详细的说明,并给出该方法在实际工程应用效果。

当前,OSGi技术已引起了学术界、工业界的高度重视,类资源装载冲突问题及其解决方法,是该领域的重要基础应用问题之一。希望通过本文对类装载冲突问题的成因与技术原理的分析,及冲突消解方法的探讨,能为该领域基础理论研究与工程化应用提供有用的支撑,并引起国内对OSGi内核基础技术的更广泛关注与深入研究。

参考文献:

[1] Huhns, M N Munindar P. Singh. Service-Oriented Computing Key Concepts and Principles [J],IEEE Internet Computing Magazine, 2005, 9(1): 75-81.

[2] Lamia Youseff, Maria Butrico, Toward a Unifed Ontology of Cloud Computing[C],GCE08, Austin, Texas, USA, 2008:1-10.

[3] OSGi Alliance, OSGi Service Platform Core Specification Release 5[EB/OL], 2012, http://www.osgi.org/Specifications/.

[4] Jingang Zhou, Dazhe Zhao, Examining OSGi from an Ideal Enterprise Software Component Model[C], ICSESS2010, Beijing University of Technology, Beijing, 2010:121-125.

[5] 林昊,曾宪杰.OSGI原理与最佳实践[M].北京:电子工业出版社,2010.

[6] 周新华,曹奇英.智能家庭网关的OSGi R3实现[J].计算机工程与设计,2005,26(2):372-374.

[7] 姜华,苗克坚.基于OSGi服务网关的温度报警系统的设计[J].计算机工程与设计,2009,30(18):4177-4179.

[8] 杨林,王晶,等.基于OSGi的移动广告平台订单系统[J].计算机系统应用,2011,20(3):32-36.

[9] 陈学文,范训礼.基于OSGi的传感器网络服务体系结构[J].计算机工程,2010,36(5):97-99.

[10] Bill Venners.深入Java虚拟机[M].2版.北京:工业机械出版社,2003.

[11] Cay S.Horstmann,Gary Cornell.Java核心技术卷Ⅱ[M].北京:工业机械出版社,2011.