2、充满玄机的初始化 string [] addInDirs = ICSharpCode.SharpDevelop.AddInSettingsHandler.GetAddInDirectories( out ignoreDefaultPath ); AddInTreeSingleton.SetAddInDirectories(addInDirs, ignoreDefaultPath); 通过AddInSettingsHandler取得插件的目录,并告知AddInTreeSingleton。AddInSettingsHandler定义在/src/Main/StartUp/Dialogs/AddInTreeSettingsHandler.cs中,它通过读取系统配置(App.config)文件中的AddInDirectory节点的Path属性来确定插件的目录位置,或者你也可以通过自己定义的AddInDirectories节来指定插件目录。如果你没有做这些配置,默认的目录在SharpDevelop运行目录的../Addins目录下。
ServiceManager.Services.AddService(new MessageService()); ServiceManager.Services.AddService(new ResourceService()); ServiceManager.Services.AddService(new IconService()); 通过ServiceManager(服务管理器)加入三个系统默认的服务,消息服务、资源服务、图标服务。这三个服务中,消息服务是显示各种信息提示,另外两个是属于系统的资源,SharpDevelop通过服务来进行统一调用和管理。
ServiceManager.Services.InitializeServicesSubsystem("/Workspace/Services"); 初始化其他的服务。SharpDevelop把服务定义在插件树的/Workspace/Services这个路径中,凡是在这个路径下的插件都被认为是服务,因此如果你自己定义了一个服务的话,也需要挂到这个路径下(这里就是系统服务的扩展点了)。 注意!这一步中,在我们的眼皮子底下悄悄的进行了一个重要的初始化工作。各位看官请看,ServiceManager 定义在/src/Main/Core/Services/ ServiceManager.cs文件中,察看它的InitializeServicesSubsystem方法,我们发现这样一行 AddServices((IService[])AddInTreeSingleton.AddInTree.GetTreeNode(servicesPath).BuildChildItems(this).ToArray(typeof(IService))); 在这里,AddInTreeSingleton首次调用了AddInTree(插件树)的实例。按照Singleton模式,只有在首次调用的时候才会初始化实例,这里也是同样如此。整个系统的AddInTree是在这一步中进行了初始化工作,稍候我们将详细介绍AddInTree如何进行初始化工作,先顺便看看服务的初始化。在ServiceManager的InitializeServicesSubsystem方法中,通过AddInTree检索服务插件路径下的所有配置,并通过它来读取、建立具体的对象,然后加入到服务列表中。之后通过一个循环,逐个的调用各个服务的InitializeService方法初始化服务。
AddInTree的初始化工作容我们稍候再看,先把主体的代码看完。 commands = AddInTreeSingleton.AddInTree.GetTreeNode("/Workspace/Autostart").BuildChildItems(null); for (int i = 0; i < commands.Count - 1; ++i) { ((ICommand)commands[i]).Run(); } /Workspace/Autostart是系统自动运行命令的扩展点路径,定义在这个路径下的插件会在系统启动的时候自动运行。在这里,通过插件树初始化建立处于这个路径下的Command(命令),并逐一执行。BuildChildItems方法的功能是建立这个扩展点下的Command列表,我会在介绍AddTree的时候具体说明它的实现。
主程序代码的最后,初始化完毕、关闭封面窗体,然后执行命令列表中最后一个命令(也就是系统的主界面)。在主界面退出的时候,系统卸载所有的服务。 在这部分代码中,我们知道了两个系统指定的扩展点路径 /Workspace/Services 和 /Workspace/Autostart ,我们实现服务和指定系统自动运行命令的时候就可以挂到这两个扩展点路径下了。 托反射的福,ServiceManager.Services可以通过类型(接口)来查找具体的实例,也就是GetServices方法。但是ServiceManager的具体实现我们可以容后再看,这里已经不是最紧要的部分了。 接下来,我们来看看整个插件系统的核心-AddinTree的代码,看看它是如何通过插件配置进行初始化并建立起整个系统的插件树骨干。