ABP vNext详细教程——模块类

概述

模块化是ABP vNext的最大亮点,也是ABP vNext框架的核心,而模块类是ABP vNext框架模块化的核心要素。

这一章节,我就从模块类的用法、运行机制、源代码等层面,带大家详细了解ABP vNext的模块类。

用法

在ABP的约定中,每个项目(类库)都应该包含一个继承自 AbpModule 的模块类,命名规范为【项目名称+Module】

在模块类中,我们可以重写 AbpModule 中的服务配置和应用初始化、服务关闭时的处理方法。.

ConfigureServices 方法用于在应用正式启动前对应用的服务的参数与依赖注入项进行配置。

在 ConfigureServices 方法中,我们可以使用 context.Services 中的方法对以来注入进行定义或修改,也可以使用  Configure<...>(); 方法对服务中的指定配置项进行配合。例如:

public override void ConfigureServices(ServiceConfigurationContext context){    //自定义依赖注入    context.Services.AddTransient<IUserRepository,UserRepostory>();
  //自定义配置  Configure<AbpClockOptions>(options =>  {    options.Kind = DateTimeKind.Local;  });}

同时,ABP也提供了异步的服务配置方法 ConfigureServicesAsync ,其用法与 ConfigureServices 相同。

另外,ABP还提供了 PreConfigureServices 和 PostConfigureServices 方法,分别在执行 ConfigureServices 前和执行后编写自己的逻辑处理,对应的,也提供异步方法 PreConfigureServicesAsync 和 PostConfigureServicesAsync 。

OnApplicationInitialization 方法在应用初始化时被执行,最常见的用途是配置管道模型,同时,也可以添加一些额外的处理,例如添加后台作业、完成服务注册等。

同时,ABP也提供了异步的服务初始化方法 OnApplicationInitializationAsync ,和在其前后的处理 OnPreApplicationInitialization 和 OnPostApplicationInitialization 

OnApplicationShutdown 方法和其异步方法 OnApplicationShutdownAsync 在程序关闭时被执行,可用于释放资源等操作。

当一个项目依赖另一个项目时,除需要引用该项目外,当前项目的模块类需要通过DependOn特性添加对被引用项目的模块类的使用,用法如下:

[DependsOn(    typeof(AbpDemoDomainModule),    typeof(AbpDemoApplicationContractsModule),    ... ...    )]public class AbpDemoApplicationModule : AbpModule{    }

运行机制

ABP框架项目启动时,会从启动项的模块类开始,按照模块类中编写的DependOn特性关系及顺序查找所有依赖模块类,并形成一个属性结构,按树形结构后序遍历算法递归遍历树形成一个模块类的列表,递归过程中如果已经加载过的模块类则被忽略。先在列表中遍历执行所有模块类的PreConfigureServices ,然后遍历执行所有模块类的 ConfigureServices ,之后同样方式执行: PostConfigureServicesAsync 、 OnPreApplicationInitialization 、 OnApplicationInitialization 、 OnPostApplicationInitialization 。

后序遍历算法时先从左到右处理所有子节点,再处理子根节点的遍历算法。

例如在ABP默认到处的框架中,依赖关系如下图所示,其中HttpApiHost为启动项(Web项目结构相同)。图中圆圈标记的序号顺序是后续遍历算法中遍历的顺序,其中蓝色圆圈表示未添加过该模块类,遍历时添加到模块类列表,红色圆圈表示已添加过,在遍历时不添加。

ABP vNext详细教程——模块类

依据图中大家可以看出,该项目模块类列表顺序为:DomainSharedModule → ApplicationContractsModule → HttpApiModule → DomainModule → ApplicationModule → EntityFrameworkCoreModule → HttpApiHostModule

也就意味着,执行顺序为:DomainSharedModule.PreConfigureServices → ApplicationContractsModule.PreConfigureServices → ... ... → HttpApiHostModule.PreConfigureServices → DomainSharedModule.ConfigureServices → ApplicationContractsModule.ConfigureServices → ... ... → HttpApiHostModule.ConfigureServices → ... ... → HttpApiHostModule.OnPostApplicationInitialization

核心源码导读

ABP模块化的所有代码都存放于ABP源码的Volo.Abp.Core项目下Volo/Abp/Modularity文件夹下:https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Core/Volo/Abp/Modularity

AbpModule 为模块类的基类,在该类中我们可以看到PreConfigureServices、ConfigureServices等方法的虚方法,和PreConfigureServicesAsync、ConfigureServicesAsync等异步的虚方法。我们可以看到这些方法中没有任何实际代码,异步方法中也只是添加了对相应的同步方法的调用。在实际项目的模块类中,我们可以依据需求重写这些方法。

AbpModuleDescriptor 是用来存储模块类信息及其依赖关系的类,其中 IReadOnlyList<IAbpModuleDescriptor> Dependencies 属性用于存储当前模块的依赖模块,以此形成树形结构。

DependsOnAttribute 是用于标记依赖关系的特性,而查找依赖关系时,是通过其继承的 IDependedTypesProvider 接口,如果需要,我们也可以通过实现此接口自定义依赖关系特性。

IModuleLoader 接口声明了加载模块列表的方法定义,其官方提供的实现类为 ModuleLoader ,源码中实现代码如下:

ABP vNext详细教程——模块类

通过该方法,实现了章节3中提到的模块类执行顺序的构建。

IModuleLifecycleContributor 是模块生命周期提供者接口,在DefaultModuleLifecycleContributor.cs文件中提供了多个该接口的实现类,分别对应应用初始化前、初始化、初始化后和应用关闭事件。

在Volo/Abp/Modularity下其他类或接口主要是对以上几个核心类的封装或者提供细节实现,这里不进行一一列举。