论文部分内容阅读
摘 要: 软件开发过程中,软件的规模越来越大,软件的需求也经常变化。为能够更好的封装变化点,提高系统的适应能力,减少修改及增加功能对原系统的影响,设计一个领域无关、松散结构、低耦合的通用插件框架是很重要的。提出基于反射的低耦合通用插件框架,该框架利用反射提供插件功能,通过框架内核动态的在插件之间传递消息,控制插件的运行,通过内核扩展机制提供合法性验证等功能,具有一定的实用价值。
关键词: 低耦合;反射;插件;微内核
中图分类号:TP311.52 文献标识码:A 文章编号:1671-7597(2012)0310054-02
0 引言
在当前社会中软件规模越来越大,并且需求的变化也越来越频繁,对软件开发周期和效率提出了越来越高的要求。软件框架是一个可复用的,与具体的应用逻辑无关的程序。相对于庞大的软件体系结构更容易被开发者理解和使用,通过对框架的配置、应用逻辑编写、简单扩展等操作即可实现应用系统。由于软件框架比较容易扩展及较大的灵活性,日益受到人们的关注和重视。
本文利用.Net提供的反射机制,设计了一种低耦合的轻量级框架(Loosely Coupled Flyweight Framework),以下简称为LCFF。此框架将软件各个业务逻辑、功能、界面等元素作为插件。各个插件在框架统一组织协调下,通过窄接口发送和接收消息,有效降低耦合性。并且各插件可进行并行开发,提高软件生产率和软件质量。
1 框架的实现策略
LCFF是一种低耦合的应用程序框架,它自身不包含和业务有关的应用逻辑。LCFF利用了.Net平台提供的反射机制来动态加载和运行插件的。本框架的结构如下图(图1),由框架微内核与内核扩展两部分组成。
1.1 微内核
LCFF的内核是LCFF基础和核心,主要用来建立和维护插件系统,加载和运行插件,根据配置对插件的事件进行接收转发等功能,不包括任何业务及界面相关的内容。LCFF内核主要有系统服务、配置管理器、插件树、对象加载器、运行态列表等几部分组成。
系统服务是一组通用的功能,在内核运行时需要这些服务的支持,它们一般为静态的方法或者是单例的对象。在内核中主要的系统服务有:FileService提供通用的文件操作,包括:绝对相对路径之间的转换、文件搜索、路径分析、URL分析等功能。PropertyService提供全局属性关系管理,具有保存/修改/删除全局属性功能,并当属性变化时会触发Property
Changed事件。ResourceService提供字符串和图像资源的管理,本地化功能主要由此服务完成。LoggingService调用log4net组件记录日志,便于跟踪程序的运行。
LCFF框架的配置文件是XML格式的文件,主要是因为XML文档结构性良好,便于理解、传输和扩展,并且XML文档得到了很多工具的支持,易于使用。LCFF的配置文件主要是配置管理器来读取和解析。配置管理器的核心是XML文件装载器和配置内容解析器。通过对框架默认配置文件的解析,将配置内容传递给内核的其它部分,以完成内核的启动。
插件树是LCFF内核的核心组成部分,在内核启动过程中,主要的工作就是根据内核配置文件和各插件的配置文件来构建系统的插件树。插件树是内核的全局静态树状结构,树中每一个结点就是一个插件的相关信息。插件树中每一个插件都有一个路径,插件是某路径上结点。路径反应了插件之间的依赖关系,运行某路径下的插件,则首先会调用其父路径下的所有结点插件。在插件树上有一些特殊的路径,对应特殊的功能。例如:内核自身信息保存在/LCFF/Core/下,系统服务的路径为/LCFF/Services/,在路径/LCFF/AutoStart/路径下的结点会在内核启动后自动运行一次。路径/Start/为启动的主界面,下面主要有Form和Console结点,对应窗体界面方式和控制台方式。当内核启动完成后,插件树就会构建完成,一般不会在内核启动后动态增加和删除插件。
LCFF是一个开放的系统,系统自身具有很强的扩展能力,在内核启动后这个系统还不具有确定的逻辑,这些逻辑以插件的形式定义,并以XML配置文件来描述和配置,所以系统的具有的功能依赖于用户的添加与裁剪,用户所做的操作仅仅是把要操作的功能集添加到某一目录并修改配置文件,不需要重新编译整个系统。对象加载器的功能就是根据插件树中插件结点的信息(程序集/属性/类型/约束),利用反射功能动态加载插件和实例化对象,为对象分配运行空间,将其加入某容器中显示,并调用入口方法开始运行。
在传统的插件模型中,如果插件之间要传递消息,则要求插件进行相互引用,在软件源代码中设置好插件之间关联,并在编译时与主程序进行正确的链接,很明显这种模式插件之间是高耦合的。在LCFF框架中,内核是独立于各插件的,内核运行后为插件创建了运行的环境。为了降低插件之间的耦合,插件只与内核通信,内核通过一个窄接口来启动插件,处于运行状态的插件实例信息在内核的运行态容器中注册,每个插件对象实例在运行态容器中都有唯一的标识。内核通过插件对象的标识来管理这些对象实例,主要有访问其公共的方法和属性、激活、接挂到某界面容器、转发消息和关闭等功能。当插件运行时,内核会查找插件树中此插件的设置,将此插件事件接挂到运行态容器中。当此插件事件触发时,内核会根据插件设置在运行态容器中查找所有接收对象,内核从事件请求对象获取事件参数信息,将这些信息传递给接收对象绑定的方法并调用该方法,在方法调用结束以后,内核会获取方法返回值,并返回给触发事件的插件实例。LCFF框架中插件之间不能直接通信,也相互不了解,通过配置文件建立关联,通过内核进行消息的转发来相互通信。显然,LCFF框架有效的降低了插件之间的耦合性。
1.2 内核扩展
LCFF框架中的内核扩展部分是对插件合法性检测、界面动态生成等方面功能的扩展。LCFF内核扩展部分主要有:自定义服务、合法性验证二个部分。内核扩展以插件形式提供,用户可以进行扩展,当然它是特殊的插件,在插件树上有固定的路径。自定义服务定义在路径/LCFF/CoreExtend
/下,常用的自定义服务有:MenuService提供了菜单的功能,ToolBarService提供了工具栏的功能,StatusService提供了状态栏的功能,MessageService提供自定义消息显示功能。合法性验证定义在路径/LCFF/PlusInValidate/下,提供验证插件的签名和版本等功能,在插件被内核实例化前运行本插件。
2 插件
2.1 插件接口
LCFF框架使用了动态函数库类型的插件模式,框架通过插件接口来实例化插件,并链接插件事件,根据配置文件来处理插件的事件。
对于插件来讲,主要实现下面的接口:
public interface IPlusIn
{
void Init();
void Run();
void DataChanged();
event DelegateDataChanged EventDataChanged;
event DelegateClosing EventPlusInClosing;
}
对于框架实例化插件后,首先调用插件的Init()方法做初始化工作,然后调用插件的Run()方法,插件开始工作。在插件工作的过程中,如果插件修改重要的数据,可以触发EventDataChanged事件通过框架,由框架转发给其它的插件。如果其它插件修改了重要数据,则框架调用插件的DataChanged()方法。当插件结构时触发EventPlusInClosing事件,框架可对插件做一些扫尾工作。
2.2 插件配置文件
插件的配置文件是插件和内核之间的连接器,LCFF内核读取插件配置信息并验证,可以知道插件的入口,插件加载位置,插件之间关联等信息。配置文件以XML格式存放。一个插件的配置文件基本内容如下:
……
在插件的配置信息中,重要的有Path,它定义了此插件在插件树上的位置。DLL对应插件的物理路径和文件名,ID是此插件的唯一标识,singleton定义此插件是否单例运行,eventAssociate是与此插件事件相关联的对象,插件初始化时,内核会把此插件数据变化事件接挂到此处设置的相关联的位于运行态容器中的对象上,事件触发时,相关联的对象会收到相应的信息。对于MenuItem和ToolBarItem项主要是用于生成界面的设置内容。
3 LCFF工作流程
框架启动过程:启动内核->验证内核的完整性->检查系统服务,并初始化系统服务->读取内核配置文件->初始化插件树->在路径/LCFF/Core/保存内核的相关信息->在路径/LCFF/Services/下接挂系统服务->查找并读取插件树配置文件->验证插件后将插件信息加入插件树指定的路径下->实例化路径/LCFF/AutoStart/下插件并运行->根据配置运行/Start/路径下的Form结点或Console结点->启动/LCFF/CoreExtend/下的服务,为主界面生成菜单、工具栏等元素->显示主界面,进行消息等待状态。
框架运行过程:捕获主界面上菜单、工具栏等元素的单击事件->内核根据元素的Tag属性值判断相应的对象->在插件树中找到相应的插件->查找处于运行态容器中的对象列表->根据对象的配置和相应插件是否处于运行态,内核会激活运行态的插件或者通过反射实例化插件->在插件了重要数据时,触发EventDataChanged事件->内核捕获该事件,根据插件配置,遍历运行态容器,找到要通知的插件,调用这些插件的DataChanged()方法->某插件关闭时,触发EventPlusInClosing事件->内核从运行态容器中去除相关插件。
4 结束语
框架设计时重要的是关注应用系统中的重用性和可扩充性,以缩短大型软件的开发周期,提高开发质量。本文提出了一种基于反射的低耦合轻量级软件框架,该框架的优点是业务与界面以插件形式运行。插件之间没能任何形式的引用。插件之间的关联通过配置文件来设置,插件之间的消息传递由内核进行接收和转发。框架自身的扩展能力也比较强,可以编写自定义服务与合法性验证插件扩展本框架。但对于本框架,还有很多方面的不足,例如:异常处理、界面控制、插件之间的复杂关系设置、消息传递、性能等内容,这些也是此框架后继研究的内容。
参考文献:
[1]王孝明、胡健等,基于.NET平台可复用软件框架的设计与实现[J].计算机工程,2004,30(22):76-78.
[2]崔冬华、刘吉林,基于反射的低耦合软件框架的研究[J].计算机信息,2007,23(10):232-234.
[3]孙玉钰,基于.NET组件技术的插件式框架的研究[J].计算机应用与软件,2009,26(6):143-145.
[4]刘佳、王丽宏等,插件技术在控制系统中的应用[J].计算应用研究,2004,3:117-118.
[5]Don Box,COM本质论[M].潘爱民译,北京:中国电力出版社,2001.
[6]Don Box、Chris Shells,NET本质论,第1卷:公共语言运行库[M].张烧坤译,北京:中国电力出版社,2004.
关键词: 低耦合;反射;插件;微内核
中图分类号:TP311.52 文献标识码:A 文章编号:1671-7597(2012)0310054-02
0 引言
在当前社会中软件规模越来越大,并且需求的变化也越来越频繁,对软件开发周期和效率提出了越来越高的要求。软件框架是一个可复用的,与具体的应用逻辑无关的程序。相对于庞大的软件体系结构更容易被开发者理解和使用,通过对框架的配置、应用逻辑编写、简单扩展等操作即可实现应用系统。由于软件框架比较容易扩展及较大的灵活性,日益受到人们的关注和重视。
本文利用.Net提供的反射机制,设计了一种低耦合的轻量级框架(Loosely Coupled Flyweight Framework),以下简称为LCFF。此框架将软件各个业务逻辑、功能、界面等元素作为插件。各个插件在框架统一组织协调下,通过窄接口发送和接收消息,有效降低耦合性。并且各插件可进行并行开发,提高软件生产率和软件质量。
1 框架的实现策略
LCFF是一种低耦合的应用程序框架,它自身不包含和业务有关的应用逻辑。LCFF利用了.Net平台提供的反射机制来动态加载和运行插件的。本框架的结构如下图(图1),由框架微内核与内核扩展两部分组成。
1.1 微内核
LCFF的内核是LCFF基础和核心,主要用来建立和维护插件系统,加载和运行插件,根据配置对插件的事件进行接收转发等功能,不包括任何业务及界面相关的内容。LCFF内核主要有系统服务、配置管理器、插件树、对象加载器、运行态列表等几部分组成。
系统服务是一组通用的功能,在内核运行时需要这些服务的支持,它们一般为静态的方法或者是单例的对象。在内核中主要的系统服务有:FileService提供通用的文件操作,包括:绝对相对路径之间的转换、文件搜索、路径分析、URL分析等功能。PropertyService提供全局属性关系管理,具有保存/修改/删除全局属性功能,并当属性变化时会触发Property
Changed事件。ResourceService提供字符串和图像资源的管理,本地化功能主要由此服务完成。LoggingService调用log4net组件记录日志,便于跟踪程序的运行。
LCFF框架的配置文件是XML格式的文件,主要是因为XML文档结构性良好,便于理解、传输和扩展,并且XML文档得到了很多工具的支持,易于使用。LCFF的配置文件主要是配置管理器来读取和解析。配置管理器的核心是XML文件装载器和配置内容解析器。通过对框架默认配置文件的解析,将配置内容传递给内核的其它部分,以完成内核的启动。
插件树是LCFF内核的核心组成部分,在内核启动过程中,主要的工作就是根据内核配置文件和各插件的配置文件来构建系统的插件树。插件树是内核的全局静态树状结构,树中每一个结点就是一个插件的相关信息。插件树中每一个插件都有一个路径,插件是某路径上结点。路径反应了插件之间的依赖关系,运行某路径下的插件,则首先会调用其父路径下的所有结点插件。在插件树上有一些特殊的路径,对应特殊的功能。例如:内核自身信息保存在/LCFF/Core/下,系统服务的路径为/LCFF/Services/,在路径/LCFF/AutoStart/路径下的结点会在内核启动后自动运行一次。路径/Start/为启动的主界面,下面主要有Form和Console结点,对应窗体界面方式和控制台方式。当内核启动完成后,插件树就会构建完成,一般不会在内核启动后动态增加和删除插件。
LCFF是一个开放的系统,系统自身具有很强的扩展能力,在内核启动后这个系统还不具有确定的逻辑,这些逻辑以插件的形式定义,并以XML配置文件来描述和配置,所以系统的具有的功能依赖于用户的添加与裁剪,用户所做的操作仅仅是把要操作的功能集添加到某一目录并修改配置文件,不需要重新编译整个系统。对象加载器的功能就是根据插件树中插件结点的信息(程序集/属性/类型/约束),利用反射功能动态加载插件和实例化对象,为对象分配运行空间,将其加入某容器中显示,并调用入口方法开始运行。
在传统的插件模型中,如果插件之间要传递消息,则要求插件进行相互引用,在软件源代码中设置好插件之间关联,并在编译时与主程序进行正确的链接,很明显这种模式插件之间是高耦合的。在LCFF框架中,内核是独立于各插件的,内核运行后为插件创建了运行的环境。为了降低插件之间的耦合,插件只与内核通信,内核通过一个窄接口来启动插件,处于运行状态的插件实例信息在内核的运行态容器中注册,每个插件对象实例在运行态容器中都有唯一的标识。内核通过插件对象的标识来管理这些对象实例,主要有访问其公共的方法和属性、激活、接挂到某界面容器、转发消息和关闭等功能。当插件运行时,内核会查找插件树中此插件的设置,将此插件事件接挂到运行态容器中。当此插件事件触发时,内核会根据插件设置在运行态容器中查找所有接收对象,内核从事件请求对象获取事件参数信息,将这些信息传递给接收对象绑定的方法并调用该方法,在方法调用结束以后,内核会获取方法返回值,并返回给触发事件的插件实例。LCFF框架中插件之间不能直接通信,也相互不了解,通过配置文件建立关联,通过内核进行消息的转发来相互通信。显然,LCFF框架有效的降低了插件之间的耦合性。
1.2 内核扩展
LCFF框架中的内核扩展部分是对插件合法性检测、界面动态生成等方面功能的扩展。LCFF内核扩展部分主要有:自定义服务、合法性验证二个部分。内核扩展以插件形式提供,用户可以进行扩展,当然它是特殊的插件,在插件树上有固定的路径。自定义服务定义在路径/LCFF/CoreExtend
/下,常用的自定义服务有:MenuService提供了菜单的功能,ToolBarService提供了工具栏的功能,StatusService提供了状态栏的功能,MessageService提供自定义消息显示功能。合法性验证定义在路径/LCFF/PlusInValidate/下,提供验证插件的签名和版本等功能,在插件被内核实例化前运行本插件。
2 插件
2.1 插件接口
LCFF框架使用了动态函数库类型的插件模式,框架通过插件接口来实例化插件,并链接插件事件,根据配置文件来处理插件的事件。
对于插件来讲,主要实现下面的接口:
public interface IPlusIn
{
void Init();
void Run();
void DataChanged();
event DelegateDataChanged EventDataChanged;
event DelegateClosing EventPlusInClosing;
}
对于框架实例化插件后,首先调用插件的Init()方法做初始化工作,然后调用插件的Run()方法,插件开始工作。在插件工作的过程中,如果插件修改重要的数据,可以触发EventDataChanged事件通过框架,由框架转发给其它的插件。如果其它插件修改了重要数据,则框架调用插件的DataChanged()方法。当插件结构时触发EventPlusInClosing事件,框架可对插件做一些扫尾工作。
2.2 插件配置文件
插件的配置文件是插件和内核之间的连接器,LCFF内核读取插件配置信息并验证,可以知道插件的入口,插件加载位置,插件之间关联等信息。配置文件以XML格式存放。一个插件的配置文件基本内容如下:
……
在插件的配置信息中,重要的有Path,它定义了此插件在插件树上的位置。DLL对应插件的物理路径和文件名,ID是此插件的唯一标识,singleton定义此插件是否单例运行,eventAssociate是与此插件事件相关联的对象,插件初始化时,内核会把此插件数据变化事件接挂到此处设置的相关联的位于运行态容器中的对象上,事件触发时,相关联的对象会收到相应的信息。对于MenuItem和ToolBarItem项主要是用于生成界面的设置内容。
3 LCFF工作流程
框架启动过程:启动内核->验证内核的完整性->检查系统服务,并初始化系统服务->读取内核配置文件->初始化插件树->在路径/LCFF/Core/保存内核的相关信息->在路径/LCFF/Services/下接挂系统服务->查找并读取插件树配置文件->验证插件后将插件信息加入插件树指定的路径下->实例化路径/LCFF/AutoStart/下插件并运行->根据配置运行/Start/路径下的Form结点或Console结点->启动/LCFF/CoreExtend/下的服务,为主界面生成菜单、工具栏等元素->显示主界面,进行消息等待状态。
框架运行过程:捕获主界面上菜单、工具栏等元素的单击事件->内核根据元素的Tag属性值判断相应的对象->在插件树中找到相应的插件->查找处于运行态容器中的对象列表->根据对象的配置和相应插件是否处于运行态,内核会激活运行态的插件或者通过反射实例化插件->在插件了重要数据时,触发EventDataChanged事件->内核捕获该事件,根据插件配置,遍历运行态容器,找到要通知的插件,调用这些插件的DataChanged()方法->某插件关闭时,触发EventPlusInClosing事件->内核从运行态容器中去除相关插件。
4 结束语
框架设计时重要的是关注应用系统中的重用性和可扩充性,以缩短大型软件的开发周期,提高开发质量。本文提出了一种基于反射的低耦合轻量级软件框架,该框架的优点是业务与界面以插件形式运行。插件之间没能任何形式的引用。插件之间的关联通过配置文件来设置,插件之间的消息传递由内核进行接收和转发。框架自身的扩展能力也比较强,可以编写自定义服务与合法性验证插件扩展本框架。但对于本框架,还有很多方面的不足,例如:异常处理、界面控制、插件之间的复杂关系设置、消息传递、性能等内容,这些也是此框架后继研究的内容。
参考文献:
[1]王孝明、胡健等,基于.NET平台可复用软件框架的设计与实现[J].计算机工程,2004,30(22):76-78.
[2]崔冬华、刘吉林,基于反射的低耦合软件框架的研究[J].计算机信息,2007,23(10):232-234.
[3]孙玉钰,基于.NET组件技术的插件式框架的研究[J].计算机应用与软件,2009,26(6):143-145.
[4]刘佳、王丽宏等,插件技术在控制系统中的应用[J].计算应用研究,2004,3:117-118.
[5]Don Box,COM本质论[M].潘爱民译,北京:中国电力出版社,2001.
[6]Don Box、Chris Shells,NET本质论,第1卷:公共语言运行库[M].张烧坤译,北京:中国电力出版社,2004.