ABP官方文档翻译 1.3 模块系统
ABP模块系统
ABP提供了创建模块并组合模块创建应用的基础设施。模块可以依赖于另一个模块。通常,一个程序集可以认为为一个模块。如果创建的应用包含多个程序集,建议为每个程序集定义一个模块。
模块系统是在服务端的不在客户端。
模块使用继承于AbpModule的类定义。比方说我们开发了一个可以用在不同应用的博客模块,最简单的定义方法如下所示:
public class MyBlogApplicationModule : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } }
如果需要的话,模块定义类负责将当前模块注册到依赖注入(如上面代码中所示)。还可以配置应用和其他模块,添加新特征到应用程序等。
ABP在应用启动和关闭的时候调用模块的一些特定方法。可以重写这些方法执行一些特定的任务。
ABP根据依赖顺序调用这些方法。如果模块A依赖于模块B,模块B会在模块A之前初始化。确切的启动方法顺序为: Preinitialize-B,PreInitialize-B,Initialize-B,Initialize-A,PostInitialize-B,PostInitialize-A。对所有的依赖关系图都是如此。Shutdown方法也相似,但是顺序相反。
当应用启动时首先被调用的方法。通常用来配置框架和其他模块,在他们初始化之前。
也可以在这个方法里写一些特定需要运行的代码在依赖注入注册之前。例如,如果创建了一个常见的注册类,可以在这里使用IocManager.AddConventionalRegisterer方法。
这里通常是依赖注入注册完成的地方。一般使用IocManagerAssemblyByConvention方法。如果想定义定制的依赖注册,参见依赖注入文档。
这个方法在启动过程中最后调用。在这里解决依赖是安全的。
这个方法当应用关闭的时候调用。
一个模块可以依赖于另一个模块。需要使用DependsOn特性显示声明依赖,如下:
[DependsOn(typeof(MyBlogCoreModule))] public class MyBlogApplicationModule : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } }
这样我们就告诉ABP,MyBlogApplicationModule 模块依赖于MyBlogCoreModule ,MyBlogCoreModule 模块应该在MyBlogApplicationModule 之前初始化。
ABP可以从启动模块开始递归解决模块依赖,并且相应的初始化模块。启动模块最后初始化。
当模块从启动模块开始研究并进入依赖关系时,ABP可以动态的加载模块。AbpBootstrapper类定义了PlugInSources属性,这个属性可以用来动态添加插件源到加载插件模块。一个插件源可以是任何实现了IplungInSource接口的类。PlugInFolderSource 类实现了这个接口,可以从一个文件夹中的程序集里获取插件模块。
在启动类中,ABP ASP.NET Core模块在AddAbp扩展方法的options中添加插件源:
services.AddAbp<MyStartupModule>(options => { options.PlugInSources.Add(new FolderPlugInSource(@"C:\MyPlugIns")); });
我们可以用简单的语法使用AddFolder扩展方法:
services.AddAbp<MyStartupModule>(options => { options.PlugInSources.AddFolder(@"C:\MyPlugIns"); });
参见ASP.NET Core 文档查看在启动类中的更多信息。
在经典的ASP.NET MVC应用中,我们可以重写在global.asax中的Application_Start方法来添加插件目录,如下所示:
public class MvcApplication : AbpWebApplication<MyStartupModule> { protected override void Application_Start(object sender, EventArgs e) { AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns"); //... base.Application_Start(sender, e); } }
如果模块中包含MVC或Web API控制器,ABP不能调查控制器。为了解决这个问题,可以按如下所示改变global.asax文件:
using System.Web; using Abp.PlugIns; using Abp.Web; using MyDemoApp.Web; [assembly: PreApplicationStartMethod(typeof(PreStarter), "Start")] namespace MyDemoApp.Web { public class MvcApplication : AbpWebApplication<MyStartupModule> { } public static class PreStarter { public static void Start() { //... MvcApplication.AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns\"); MvcApplication.AbpBootstrapper.PlugInSources.AddToBuildManager(); } } }
IAssemblyFinder 和 ITypeFinder(ABP用来调查应用中的特定类) 的默认实现只查找模块程序集和在这些程序集中的类型。我们可以重写我们模块中的GetAdditionalAssemblies 方法把额外的程序集包含进来。
模块中可以有自定义方法,这些方法可以被其他的依赖于本模块的模块调用。假定MyModule2依赖于MyModule1,并且想在PreInitialize方法调用MyModule1的一个方法。
public class MyModule1 : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } public void MyModuleMethod1() { //this is a custom method of this module } } [DependsOn(typeof(MyModule1))] public class MyModule2 : AbpModule { private readonly MyModule1 _myModule1; public MyModule2(MyModule1 myModule1) { _myModule1 = myModule1; } public override void PreInitialize() { _myModule1.MyModuleMethod1(); //Call MyModule1's method } public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } }
这里,使用构造注入把MyModule1注入到MyModule2,这样MyModule2就能够调用MyModule1的方法了。这种情况只有Module2依赖于Module1的情况下才可以。
虽然自定义模块方法可以配置模块,但我们建议使用启动配置系统定义、设置模块的配置。
模块类自动注册为单例的。