模块Module是ABP框架体系很重要的概念,不同的功能组件包括项目之间都是以模块的形式进行关联的。在ABP框架的启动过程中,模块的遍历、初始化、启动也是很重要的一环。


1.模块的定义

1.1定义

在ABP框架中定义了基类AbpModule,只要是继承自AbpModule的类就是模块。先来看看这个基类的定义。

namespace Abp.Modules
{public abstract class AbpModule{//获取对IOC管理器的引用protected internal IIocManager IocManager { get; internal set; }// 获取对ABP配置项的引用protected internal IAbpStartupConfiguration Configuration { get; internal set; }// 获取或设置日志public ILogger Logger { get; set; }protected AbpModule(){Logger = NullLogger.Instance;}// 预初始化public virtual void PreInitialize(){}// 初始化public virtual void Initialize(){}//初始化后public virtual void PostInitialize(){}// 关闭public virtual void Shutdown(){}public virtual Assembly[] GetAdditionalAssemblies(){return new Assembly[0];}// 检查是否为模块public static bool IsAbpModule(Type type){var typeInfo = type.GetTypeInfo();returntypeInfo.IsClass &&!typeInfo.IsAbstract &&!typeInfo.IsGenericType &&typeof(AbpModule).IsAssignableFrom(type);}// 查找依赖模块public static List<Type> FindDependedModuleTypes(Type moduleType){if (!IsAbpModule(moduleType)){throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);}var list = new List<Type>();if (moduleType.GetTypeInfo().IsDefined(typeof(DependsOnAttribute), true)){var dependsOnAttributes = moduleType.GetTypeInfo().GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>();foreach (var dependsOnAttribute in dependsOnAttributes){foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes){list.Add(dependedModuleType);}}}return list;}//根据给定的模块递归查找其所依赖的模块public static List<Type> FindDependedModuleTypesRecursivelyIncludingGivenModule(Type moduleType){var list = new List<Type>();AddModuleAndDependenciesRecursively(list, moduleType);list.AddIfNotContains(typeof(AbpKernelModule));return list;}//递归添加模块和依赖private static void AddModuleAndDependenciesRecursively(List<Type> modules, Type module){if (!IsAbpModule(module)){throw new AbpInitializationException("This type is not an ABP module: " + module.AssemblyQualifiedName);}if (modules.Contains(module)){return;}modules.Add(module);var dependedModules = FindDependedModuleTypes(module);foreach (var dependedModule in dependedModules){AddModuleAndDependenciesRecursively(modules, dependedModule);}}}
}

在AbpModule中可以看到其内部以接口形式定义了IoC管理器、模块配置项和日志组件,此外还有模块的生命周期事件和查找当前模块所依赖模块的方法。

1.2生命周期

在AbpModule可以看到模块的四个生命周期事件:

生命周期事件 说明
PreInitialize 预初始化:在初始化之前配置框架和其他模块。能够在依赖注入注册之前,在这个方法中指定需要注入的自定义启动类
Initialize 初始化:一般是来进行依赖注入的注册,常通过 IocManager.RegisterAssemblyByConvention 来实现
PostInitialize 初始化后:用来解析依赖关系
Shutdown 关闭:当应用关闭以后被调用

对于任意一个模块,这四个方法的执行顺序依次为PreInitialize–>Initialize–>PostInitialize–>Shutdown。

2.模块的依赖

2.1特性

ABP框架提供了DependsOn属性来显式说明模块间的依赖关系。可以看到DependsOn属性支持的是数组,所以一个模块可以依赖于多个模块。

namespace Abp.Modules
{[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]public class DependsOnAttribute : Attribute{public Type[] DependedModuleTypes { get; private set; }public DependsOnAttribute(params Type[] dependedModuleTypes){DependedModuleTypes = dependedModuleTypes;}}
}

再来看看示例解决方案中各模块的依赖关系。

//Web项目--呈现与分布式服务层
[DependsOn(typeof(AbpDemoApplicationModule), typeof(AbpDemoEntityFrameworkCoreModule), typeof(AbpAspNetCoreModule))]
public class AbpDemoWebModule : AbpModule
{//to do
}//EntityFrameworkCore项目--基础设施层
[DependsOn(typeof(AbpDemoCoreModule), typeof(AbpEntityFrameworkCoreModule))]
public class AbpDemoEntityFrameworkCoreModule : AbpModule
{// to do
}//Application项目--应用层
[DependsOn(typeof(AbpDemoCoreModule), typeof(AbpAutoMapperModule))]
public class AbpDemoApplicationModule : AbpModule
{// to do
}//Core项目--领域层
public class AbpDemoCoreModule : AbpModule
{// to do
}

3.模块的启动

3.1启动顺序

对于每个模块都用同样的生命周期事件,但是有多个模块而且这些模块互相之间存在依赖关系时,这些生命周期事件又该如何执行?对于这种情况,ABP框架作了清晰的定义:所有模块执行完PreInitialize预初始化方法后,所有模块再执行Initialize初始化方法,之后所有模块再执行PostInitialize初始化后方法。在ABP框架的启动过程中也遵循这一流程。
现在再回到AbpBootstrapper的Initialize初始化方法中,仔细查看模块启动的全过程。

   _moduleManager = IocManager.Resolve<AbpModuleManager>();_moduleManager.Initialize(StartupModule);_moduleManager.StartModules();
3.1.1 实例化模块管理器

在AbpBootstrapper的Initialize初始化方法中,首先是通过IocManager实例化一个模块管理器AbpModuleManager,模块管理器负责对程序中用到的模块进行管理。


3.1.2 初始化模块管理器

之后模块管理器开始对所有模块进行初始化。从下面的代码可以看出来,首先是实例化一个模块的集合AbpModuleCollection,这个模块的集合以启动模块xxxWebModule起点开始遍历。LoadAllModules就是遍历所有模块的方法。

 public virtual void Initialize(Type startupModule){_modules = new AbpModuleCollection(startupModule);LoadAllModules();}private void LoadAllModules(){Logger.Debug("Loading Abp modules...");List<Type> plugInModuleTypes;var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList();Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");//注册模块RegisterModules(moduleTypes);CreateModules(moduleTypes, plugInModuleTypes);//确保Kernel模块排在第一_modules.EnsureKernelModuleToBeFirst();//确保启动模块排在最后_modules.EnsureStartupModuleToBeLast();SetDependencies();Logger.DebugFormat("{0} modules loaded.", _modules.Count);}

在LoadAllModules方法中,除了遍历所有模块以及他们所依赖的模块外,还将这些模块进行了排序,确保AbpKernelModule这个核心模块能排在最前面首先启动,确保Web项目的启动模块xxxWebModule能排在最后。

3.1.3启动模块

启动模块的过程就是按照模块的排序,依照模块的生命周期顺序执行。首先是所有模块的预初始化,之后是所有模块的初始化,最后是所有模块的初始化后。

 public virtual void StartModules(){var sortedModules = _modules.GetSortedModuleListByDependency();sortedModules.ForEach(module => module.Instance.PreInitialize());//预初始化sortedModules.ForEach(module => module.Instance.Initialize());//初始化sortedModules.ForEach(module => module.Instance.PostInitialize());//初始化后}

3.2 AbpKernelModule

在所有模块启动的过程中,有一个要注意的是第一个预初始化的模块AbpKernelModule。这个模块的重要新从它的名称和排序上就能看出来。

public sealed class AbpKernelModule : AbpModule
{public override void PreInitialize(){//注册过滤器与基础组件IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar());IocManager.Register<IScopedIocResolver, ScopedIocResolver>(DependencyLifeStyle.Transient);IocManager.Register(typeof(IAmbientScopeProvider<>), typeof(DataContextAmbientScopeProvider<>), DependencyLifeStyle.Transient);AddAuditingSelectors();AddLocalizationSources();AddSettingProviders();AddUnitOfWorkFilters();ConfigureCaches();AddIgnoredTypes();AddMethodParameterValidators();AddDefaultNotificationDistributor();}public override void Initialize(){//foreach (var replaceAction in ((AbpStartupConfiguration)Configuration).ServiceReplaceActions.Values){replaceAction();}IocManager.IocContainer.Install(new EventBusInstaller(IocManager));IocManager.Register(typeof(IOnlineClientManager<>), typeof(OnlineClientManager<>), DependencyLifeStyle.Singleton);IocManager.Register(typeof(IOnlineClientStore<>), typeof(InMemoryOnlineClientStore<>), DependencyLifeStyle.Singleton);IocManager.Register(typeof(EventTriggerAsyncBackgroundJob<>), DependencyLifeStyle.Transient);IocManager.RegisterAssemblyByConvention(typeof(AbpKernelModule).GetAssembly(),new ConventionalRegistrationConfig{InstallInstallers = false});}public override void PostInitialize(){RegisterMissingComponents();IocManager.Resolve<SettingDefinitionManager>().Initialize();IocManager.Resolve<FeatureManager>().Initialize();IocManager.Resolve<PermissionManager>().Initialize();IocManager.Resolve<LocalizationManager>().Initialize();IocManager.Resolve<NotificationDefinitionManager>().Initialize();IocManager.Resolve<NavigationManager>().Initialize();if (Configuration.BackgroundJobs.IsJobExecutionEnabled){var workerManager = IocManager.Resolve<IBackgroundWorkerManager>();workerManager.Start();workerManager.Add(IocManager.Resolve<IBackgroundJobManager>());}}}

从这个模块的实现代码就能看出来,ABP框架核心的处理都在这里进行了。

ABP学习实践(十二)--模块系统相关推荐

  1. 吴恩达《机器学习》学习笔记十二——机器学习系统

    吴恩达<机器学习>学习笔记十二--机器学习系统 一.设计机器学习系统的思想 1.快速实现+绘制学习曲线--寻找重点优化的方向 2.误差分析 3.数值估计 二.偏斜类问题(类别不均衡) 三. ...

  2. Mysql学习总结十二:系统变量、用户变量、定义条件和处理程序

    Mysql学习总结十二:系统变量.用户变量.定义条件和处理程序 1.变量 1.1 系统变量 1.1.1 系统变量的分类 1.1.2 查看系统变量 1.2 用户变量 1.2.1 用户变量的分类 1.2. ...

  3. ABP学习实践(十六)--领域驱动设计(DDD)回顾

    ABP框架并没有实现领域驱动设计(DDD)的所有思想,但是并不妨碍用领域驱动的思想去理解ABP库框架. 1.领域驱动设计(DDD)与微服务(MicroService)的关系? 领域驱动设计(DDD)是 ...

  4. ABP学习实践(十五)--缓存使用总结

    近期在工作过程中对ABP框架的缓存功能又有了深一步的理解,做一个小小的总结. 1.关于缓存 现在相当一部分小伙伴听到缓存立刻想到Redis,反应很快,但容易进入一个误区"处理缓存就要用Red ...

  5. Python语言入门这一篇就够了-学习笔记(十二万字)

    Python语言入门这一篇就够了-学习笔记(十二万字) 友情提示:先关注收藏,再查看,12万字保姆级 Python语言从入门到精通教程. 文章目录 Python语言入门这一篇就够了-学习笔记(十二万字 ...

  6. ROS学习笔记十二:使用roswtf

    ROS学习笔记十二:使用roswtf 在使用ROS过程中,roswtf工具可以为我们提供ROS系统是否正常工作的检查作用. 注意:在进行下列操作之前,请确保roscore没有运行. 检查ROS是否安装 ...

  7. OpenCV学习笔记(十二)——图像分割与提取

    在图像处理的过程中,经常需要从图像中将前景对象作为目标图像分割或者提取出来.例如,在视频监控中,观测到的是固定背景下的视频内容,而我们对背景本身并无兴趣,感兴趣的是背景中出现的车辆.行人或者其他对象. ...

  8. C++语言学习(十二)——C++语言常见函数调用约定

    C++语言学习(十二)--C++语言常见函数调用约定 一.C++语言函数调用约定简介 C /C++开发中,程序编译没有问题,但链接的时候报告函数不存在,或程序编译和链接都没有错误,但只要调用库中的函数 ...

  9. Tensorflow深度学习之十二:基础图像处理之二

    Tensorflow深度学习之十二:基础图像处理之二 from:https://blog.csdn.net/davincil/article/details/76598474   首先放出原始图像: ...

最新文章

  1. 《Science》评选2017年十大科学突破,看看有哪些吧!
  2. avcodec_decode_video2 第三个参数 got_picture_ptr 的含义
  3. R树 mysql_为什么MySQL使用B+树作为索引
  4. HDU - 6191 Query on A Tree
  5. 《iOS9开发快速入门》——第2章,第2.1节Xcode 7.0的新特性
  6. Java中常见数据结构:list与map -底层如何实现
  7. Java 多维数组 三维数组 初始化 赋值 打印
  8. 密码库LibTomCrypt学习记录——(2)分组密码算法的工作模式
  9. ccc tiledmap
  10. mysql 8安装方法_Mysql8.0.17安装教程【推荐】
  11. HTML视频:视频播放网页
  12. AI面相手相V3.2.0无限多开版h5公众号版本源码(含搭建教程+运营文案图片)
  13. NameNode处理上报block块逻辑分析
  14. 如果在做项目时,发现自己在规定的时间内肯定完成不了时,你会怎么办
  15. 习题3-4 统计学生成绩(15 分)
  16. Docker仓库harbor
  17. matlab对信号积分,对信号求积分 - Simulink - MathWorks 中国
  18. 经验之谈-关于实际项目微前端优化
  19. 数字纪念馆设计案例,科技助力见证历史!
  20. 项目背景以及游戏平台简介

热门文章

  1. 高级软考项目管理课第一章后习题
  2. excel爬虫相关学习2:vba 爬虫相关xmlhttp
  3. [羊城杯2020]easyphp --- 伪协议的使用时机,---python上传.htaccess的利用 -- preg_match绕过
  4. win10安装CUDA9.2过程记录
  5. 盘它!H3C X3至尊版无线路由器评测
  6. Python模拟谷歌浏览器获取网页内容,反反爬虫
  7. 阿里云弹性公网IP(EIP)带宽最大值可选1000Mbps
  8. 服务器共享文件夹指定ip访问,教大家设置禁止特定IP访问共享文件
  9. c++,c->循环与分支,格物致知,下节课再见
  10. 【LGR-073】洛谷 7 月月赛 Div.2 B 混凝土数学