基于OSGi的军用指挥软件插件机制研究
2019-06-13宋文婷赵建新高腾飞
宋文婷,赵建新,艾 冰,高腾飞
(北方自动控制技术研究所,太原 030006)
0 引言
军用指挥软件在指挥信息系统中起着举足轻重的作用。大型指挥软件涉及到指挥业务、态势感知、组织筹划、情报侦察、综合保障、网络通信等方面[1],这些功能通常并行开发,再统一集成。.NET平台自被微软推出后,依靠其跨语言、跨平台、提供面向对象开发支持的优势,逐步取代了Win32 API在Windows桌面开发中的显赫地位,成为未来大型军用指挥软件开发的重要平台。
在.NET平台传统开发模式中,各功能模块在集成时需部署在一起,缺乏模块调用的统一机制,易造成依赖混乱;公用模块重复开发,资源浪费;模块间耦合度高,牵一发而动全身;系统可扩展性差,成为制约大型军用指挥软件团队开发的瓶颈问题,急需设计在.NET平台下支持并行开发、模块间松耦合、组件重用性高、便于扩展的插件机制。
插件是可以独立开发、部署的单元,可以动态地安装到运行容器中,在不修改应用主体的情况下扩展原有系统的功能,而不对其产生影响。采用插件机制能够快速分解和解决问题、实现应用功能、方便版本管理,能够针对特定需求定制功能集合、简化用户界面、减少内存耗费,提高指挥软件的易用性和高效性[2]。
.NET平台上的插件机制,以微软推行的解决方案为主[3],包括组件对象模型(COM)、动态链接库(DLL)、MEF、MAF、SharpDevelop 等。COM 组件技术及DLL方式缺乏对插件的统一管理功能、插件间调用方式单一、软件规模达到一定程度容易出现逻辑混乱,无法满足大型指挥软件系统的开发;MEF、MAF、SharpDevelop技术在插件动态加载方面不足,不支持“即插即用”。
本文采用OSGi(全称:Open Service Gateway Initiative,开放服务网关规范)[4]规范在.NET平台实现插件的加载与管控,将功能模块设计为拥有独立目录结构、相互隔离、可以“即插即用”的指挥软件插件,满足大型软件团队并行开发、插件化调用、扩展方便的要求。
1 基本原理介绍
OSGi一方面指OSGi Alliance组织,另一方面指该组织制定的基于Java语言的服务规范——OSGi服务平台。该平台支持模块化与插件化、具有热插拔与动态特性、支持SOA、支持插件扩展、提供安全性等[6]。OSGi与现有插件技术对比见表1。
OSGi插件结构在形式上分独立的宿主程序和多个互不相关的功能插件,各部分能够共同形成一个逻辑上的完整系统[7]。宿主程序完成基本系统功能,可以加载多个不同的功能插件,接受插件提供的服务并提供给用户,是整个插件系统的基础和主干。功能插件能动态加载到插件系统中,提供相对单一的功能,多个插件使系统功能完善,完成许多复杂的处理,是插件系统的重要构成部分。
根据OSGi规范,插件结构如图1所示,每个插件对应一个文件夹,由插件清单配置文件Manifest.xml和插件程序集组成。
程序数据流程大致为:运行启动后,宿主程序遍历插件目录,将包含Manifest.xml的目录识别为插件,根据该文件中信息(包括插件名称、特征名称、版本、初始状态等)创建插件对象,设置该插件状态为安装状态;当插件目录下所有插件安装完成后,宿主程序逐个解析插件间依赖关系;完成目录下插件的解析后,加载Manifest.xml中指定的程序集启动插件;如果没有抛出异常,插件启动成功,状态变为活动状态,插件被加载到程序中;当不需要运行某插件时,可以停止或卸载,状态变为停止或已卸载状态。
采用基于OSGi的插件机制开发军用指挥软件是把各大功能模块划分为不同插件,每个插件完成相对独立的功能,各插件之间以及插件与宿主程序之间通过标准接口进行集成。有利于减轻软件开发者负担,增强软件的可扩展性。
表1 现有插件技术与OSGi的对比
2 技术实现
2.1 OSGi插件化实现
采用OSGi插件机制,将插件分为宿主程序和功能插件[4]。宿主程序是功能插件运行的容器,提供环境初始化、宿主程序的启动、注销、功能插件注册等功能;功能插件就是指挥软件具体功能的实现。
插件化的实现原理如图2所示,定义IBundle为公共接口类,负责提供获取插件上下文、读取插件Manifest.xml文件等初始化接口,以及启动、停止,卸载、更新插件等插件操作类接口;定义IFrameWork继承IBundle作为宿主程序接口类;此外,为宿主程序定义了4个接口:触发事件接口IFrameworkFireEvent、服务接口IFrameworkService、监听器接口 IFrameworkListener、安装器接口IFrameworkInstaller。
图2 插件接口类图
宿主程序类Framework继承并实现IFramework、IFramework Fire Event、IFramework Service、IFrameworkListener、IFrameworkInstaller接口;功能插件类Bundle实现IBundle接口,具体实现接口中申明的方法。
2.2 插件加载
插件加载是从本插件的类型空间加载需要的类型。插件运行所需的程序集并不位于同一目录,通过设计类加载器,使其能够从插件目录中正确加载到插件程序集,采用显式加载和隐式加载两种。显式加载通过Type.GetType方法支持;隐式加载则通过对 CLR Loader扩展来支持[3]。
2.2.1 显式加载
插件可用的类型空间由本地程序集、子插件本地程序集、依赖的程序集和子插件依赖的程序集组成。这些信息配置在Manifest.xml文件中。加载的顺序为:系统库、本地Import(引用另一个插件共享的类型)、Import对应的Export信息(把本地程序集包含的类向其他插件暴露)、Require的 Bundle Dynamic Import(引用另一个插件定义的所有的Export暴露出来的所有类)。
显示加载需要使用Type.GetType(name)方法。如果类型名称没有包含程序集全名,则从正在执行的程序集和mscorlib.dll加载类型;如果指定了程序集全名,则先加载程序集,在进行类的加载。
2.2.2 隐式加载
隐式类型加载用于解决插件间的静态依赖,即一个插件在实现中直接引用了另一个插件的类的情况,通过CLR Loader触发完成加载程序集、插件、资源和类型,为了使CLR能够成功从依赖的插件加载到需要的类型,对CLR类加载器进行扩展,通过监听AppDomain的AssemblyResolve事件,匹配各插件的程序集全名,加载所需的程序集:
2.3 插件扩展
插件采用引用服务、定义扩展点两种方式实现扩展式设计。
1)引用服务,插件通过引用服务接口来获取系统中的服务,完成现插件功能的扩展。即采用传统的面向对象方式实现:引用定义服务的插件并实现对应接口,完成功能扩展。
2)定义扩展点[8],在 Manifest.xml文件中定义插件扩展信息,包括可扩展点和扩展点。可扩展点是指一个插件暴露给其他插件,可用于扩展的信息;扩展点则定义了插件对其他插件的扩展。扩展点结构如图3所示。
图3 扩展点结构
插件通过暴露扩展点提供给其他插件,实现新功能的添加。扩展点信息定义如图4所示。被扩展插件和扩展插件通过扩展点建立关联,扩展点通过ExtensionPoint节点定义并指定Point属性(即扩展点名称);扩展则通过Extension定义并指定Point属性(即扩展点名称),并在子节点定义扩展的信息。
插件扩展具有动态性[9],在插件启动时暴露扩展点供其他插件使用,并通过GetExtension方法和ExtensionChanged事件获取其他插件对该扩展点的所有扩展信息并监听扩展信息的变更;在插件停止时从宿主程序中卸载,对其他插件并不造成影响,保证了插件间的松耦合。
2.4 插件通信
插件间通信采用两种通信方式。一种是通过CLR完成,即直接通过引用类型来进行通信,用于与底层基础插件通信;另一种是插件之间通过服务来实现交互[10-11],如图5所示,插件以接口的形式定义契约(规定服务方法和数据类型),服务提供者插件对契约中约定的服务进行实现,将实现的服务对象注册到服务总线上,服务消费者插件从服务总线上获取需要的服务对象,进行调用。
图4 扩展点描述
图5 插件通信
2.5 开发平台载入
本文基于Visual Studio的模板和向导程序来实现功能插件与编程平台的紧密结合,为软件开发者提供便捷的二次开发平台,实现插件复用、提高软件开发效率。
插件项目模板及向导程序用于创建自定义的项目[12-13],根据上文描述的功能插件整理出项目模板,其中包含项目所需的目录和公共文件(如配置文件、资源文件)。
设计支持线性步骤系列的应用程序作为向导。向导中提供各个自定义参数值的输入界面、处理启动项目创建的事件,事件接收用户启动项目时所输入的项目名称,从.NET提供的IWizard接口中读取replacementsDictionary作为系统参数。根据系统参数和自定义参数,基于项目模板向导快速生成各个项目。
3 应用实例
本文在.NET平台上应用OSGi规范实现了军用指挥软件的插件机制,该机制已应用到某外贸合成旅指挥软件的开发中。该软件中软件框架包括菜单、工具栏、按钮和快捷键等[14],均采用上文所述插件机制集成,快速实现应用软件的框架构建。
以军用指挥软件中辅助计算功能模块为例:
通用模块开发人员按照上文所述的插件设计方式完成该功能开发、测试,如下页图6(a)所示;
将功能模块集成到VisualStudio开发工具中[15],如图6(b)所示;
图6 应用实例
在某外贸合成旅指挥软件中需加载该功能,开发人员无需进行重复开发,采用Visual Studio中完成加载,在图6(c)所示的向导中输入自定义参数;
将辅助计算功能加载到指挥软件中,效果如图6(d)所示。
4 结论
本文在.NET平台上借鉴OSGi规范设计了一种军用指挥软件的插件机制,为开发人员提供了简单、易用的接口,降低了系统耦合性;制定了开发规范,有助于提高开发效率、并行性和灵活性,缩短开发周期。