我设想的可扩展结构(插件) (二)

 

第一部分见:我设想的可扩展结构(插件) ()




经过一段时间的实践,一些想法也发生了变化:

1.                部署。使用软件派送系统将插件从服务器派送到客户端,并且将文件存放到一个被监控的目录下。

2.                接口。所有的插件都必须实现IPlugin接口。主程序使用此接口来操作插件。IPlugin接口包括两个方法:Execute(IAppContext context)Dispose()Execute表示执行插件中定义的动作,Dispose则表示终止执行且释放资源。

3.                插件组。除了插件类要继承一个接口外,还将DLL文件加一个Assembly级别的Attribute,用来描述该DLL文件中插件类的名字以及此插件所从属的模块名。这里约定好在一个DLL文件中只包含一个插件类,并且将众多的插件人为地划分为几个模块(业务逻辑上的划分)。插件管理程序加载DLL文件后读取此Attribute就可以知道插件类的名字,而无须再遍历DLL中所有的类型且判断其是否支持插件接口来得到插件类的名字了。为了能在一定程度上让插件之间不互相影响,为一个模块创建一个应用程序域(AppDomain)──不把所有的插件加载到同一个应用程序域中,也不为每个插件都创建一个应用程序域。如果在同一个应用程序域中运行插件则当要新版本插件来了以后,就得停掉所有的插件(因为要卸载整个AppDomain)来重新加载此插件;而如果为每个插件都创建一个应用程序域的话,势必需要创建过多的AppDomain了,所以人为将插件划分为几组以获得一个平衡。

4.                数字签名。自己开发的插件将使用一个数字签名软件为其加入数字签名,从而保证插件管理程序不会加载不合法的插件。

5.                主程序和插件通信。主程序将IAppContext对象传递给插件,从而插件可以得知运行环境方面的信息。

6.                插件之间的通信。插件之间一般不需要通信。如果需要,则增加包装类来描述该插件和其它插件的关系,通过该类来获得其它插件的实例,然后通过公共接口进行操作。

7.                新增插件以及插件版本升级。使用FileSystemWatcher类来监控存放插件的目录A(软件派送系统将所有插件存放到此目录),不过使用中会遇到一点麻烦:从别的目录拷贝一个文件到被监控的目录A后,会触发Create事件一次,Change事件两次(因为文件创建时间和文件存取时间被修改了),而后面的两次Change事件不是我们想要的;为解决这个问题,我另外设立一个目录B,一旦被监控目录中有文件加入后,我就将此文件移动到目录B,插件管理程序从目录B中Shadow Copy插件并加载之。加载的时候需要先检查此插件所属模块的AppDomain是否已经创建了,如果有的话且是新添加的插件,则在此AppDomain中加载之;如果是版本升级的插件,则卸载此AppDomain,然后重新创建之,再加载属于此模块的所有插件。

8.                远程控制插件。远程控制台上可以得到已加载插件的信息,包括插件DLL文件的名字,从属的模块和插件类名;并且可以发命令停掉或者删除某个插件。当客户端收到停止插件的命令后,插件管理程序调用IPlugin接口的Dispose方法;当收到删除插件的命令后,插件管理程序先调用Dispose方法,从内存中卸载此插件,最后将插件文件删除。

9.                插件执行Schedule。插件分为下面几种:(1)每次客户端起动后都加载执行──这样的插件区分插件组;(2)拥有执行日程的插件──总是在单独的AppDomain中加载和执行。

10.        动态编译源代码为DLL文件。可以使用CompilerICodeCompilerCodeDomProvider来对代码进行动态编译,从而生成插件的DLL文件。不过在实际应用中恐怕这么做意义不大。

 

现在我的设计已经基本出来了,但代码还在调试中,请各位继续关注我的下篇随笔,我将把设计和关键代码贴出来。希望大家继续提出看法!

posted @ 2005-07-04 14:54  风满袖  阅读(2696)  评论(10编辑  收藏  举报