模块简介
整个ABP框架可以说是由模块组成的,也可以认为是每一个程序集就是一个模块,但也不是绝对的。一个程序集也可以有多个模块.
在我们从ABP官网创建项目时,可以发现每个层下面都是有个xxxxxModule.cs的文件这就是模块.[DependsOn(typeof(MyStudyApplicationModule),typeof(MyStudyEntityFrameworkModule),typeof(AbpAspNetCoreModule),typeof(AbpAspNetCoreSignalRModule))]public class MyStudyWebCoreModule : AbpModule{}
前一篇分析启动入口时,说过在中间件注册时(UseAbp)内部会从ioc容器中获取一个AbpBootStrapper对象并执行它的Initialize方法,Initialize则会从容器中获取一个AbpModuleManager模块管理者对象,执行AbpModuleManager的Initialize方法,创建AbpModuleCollection集合,然后执行LoadAllModules加载所有模块,加载所有模块完毕后,AbpModuleManager的Initialize方法结束,开始执行AbpModuleManager.StartModules启动所有的模块.
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());}
可以看到上述代码中模块的生命周期方法:
- PreInitialize 预初始化
- Initialize 初始化
- PostInitialize 初始化完毕 但其实还有个
- Shutdown 销毁 看代码可以得知先执行的是 PreInitialize->Initialize->PostInitialize 而Shutdown则在上一篇分析过,其实是在AbpBootstrapper.Dispose方法中的ShutdownModules方法执行的,也就是程序退出的时候. 模块的用途就是在Abp框架加载的时候,执行一些初始化的操作. 例如.你可能会在xxxxxxModule看到如下代码.
public override void Initialize(){ IocManager.RegisterAssemblyByConvention(typeof(xxxxxxModule).GetAssembly());}
这其实就是模块的初始化方法,扫描当前模块所在程序集,往ioc容器注册里面需要依赖注入的类型.
其实Abp自身也有许多模块,例如AbpKernelModule这是Abp核心模块.public override void PreInitialize(){ IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar()); IocManager.Register(DependencyLifeStyle.Transient); IocManager.Register(typeof(IAmbientScopeProvider<>), typeof(DataContextAmbientScopeProvider<>), DependencyLifeStyle.Transient); AddAuditingSelectors(); AddLocalizationSources(); AddSettingProviders(); AddUnitOfWorkFilters(); ConfigureCaches(); AddIgnoredTypes(); AddMethodParameterValidators(); AddDefaultNotificationDistributor();}
PreInitialize
- 注册许多拦截器和基础组件
- 注册过滤器
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.RegisterAssemblyByConvention(typeof(AbpKernelModule).GetAssembly(),new ConventionalRegistrationConfig{InstallInstallers = false});}
Initialize
- 执行替换服务的 Action(Abp 允许用户在预加载操作替换基础设施的服务)
- 注册事件总线基础设施
- 注册AbpKernelModule所在程序集需要依赖注入的服务
public override void PostInitialize(){ RegisterMissingComponents(); IocManager.Resolve().Initialize(); IocManager.Resolve ().Initialize(); IocManager.Resolve ().Initialize(); IocManager.Resolve ().Initialize(); IocManager.Resolve ().Initialize(); IocManager.Resolve ().Initialize(); if (Configuration.BackgroundJobs.IsJobExecutionEnabled) { var workerManager = IocManager.Resolve (); workerManager.Start(); workerManager.Add(IocManager.Resolve ()); }}
PostInitialize
- 注册一些基础设施
- 从容器中取出一些服务,执行初始化方法
- 启动所有后台工作者
public override void Shutdown(){ if (Configuration.BackgroundJobs.IsJobExecutionEnabled) { IocManager.Resolve().StopAndWaitToStop(); }}
- Shutdown则很简单,停止所有后台工作.
发现模块与注册模块
搜索所有定义的模块类型
我们定义好自己的模块后,Abp又是如何知道的呢?
其实在Stratup的ConfigureServices方法中已经传入了启动模块return services.AddAbp<MyStudyWebHostModule>();
在之前 AbpBootstrapper 的 Initialize 初始化方法当中通过调用 AbpModuleManager.Initialize(StartupModule)
方法来初始化,在其内部可以看到: public virtual void Initialize(Type startupModule){ _modules = new AbpModuleCollection(startupModule); LoadAllModules();}
这里通过传入启动模块类型来初始化一个**_modules(AbpModuleCollection)**集合
internal class AbpModuleCollection : List{ public Type StartupModuleType { get; } public AbpModuleCollection(Type startupModuleType) { StartupModuleType = startupModuleType; }}
创建**_modules(AbpModuleCollection)后,执行LoadAllModules**加载所有模块
private void LoadAllModules(){ Logger.Debug("Loading Abp modules..."); ListplugInModuleTypes; var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList(); Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total."); RegisterModules(moduleTypes); CreateModules(moduleTypes, plugInModuleTypes); _modules.EnsureKernelModuleToBeFirst(); _modules.EnsureStartupModuleToBeLast(); SetDependencies(); Logger.DebugFormat("{0} modules loaded.", _modules.Count);}
- FindAllModuleTypes 寻找所有ABP模块
- RegisterModules(moduleTypes) 向ioc容器以单例的形式注册找到的ABP模块
- CreateModules(moduleTypes, plugInModuleTypes) 通过ioc容器获取模块,并创建对应的AbpModuleInfops:为什么要在包装一层呢?其实主要是因为AbpModuleInfo里包含了
public List<AbpModuleInfo> Dependencies { get; }
这个属性,里面记录了该模块的所有依赖模块,为了保证模块加载顺序正确 - _modules.EnsureKernelModuleToBeFirst 将核心模块放在第一个位置,第一个初始化
- _modules.EnsureStartupModuleToBeLast 将启动模块放在最后一个位置,最后一个初始化
- SetDependencies 设置刚才所有创建的AbpModuleInfo的依赖顺序 ps:CreateModules里会把创建的AbpModuleInfo添加进 一开始通过启动模块类型创建的AbpModuleCollection集合
private AbpModuleCollection _modules;
这其实很容易想明白,启动模块依赖于其他模块.如果初始化的顺序不对就是有问题,所以最依赖最核心的模块必须是第一个初始化的。 那么如何发现的呢. 其实是通过反射获取了标记public class DependsOnAttribute : Attribute
这个特性,取到模块类型. 我们进入FindAllModuleTypes看看
private ListFindAllModuleTypes(out List plugInModuleTypes){ plugInModuleTypes = new List (); var modules = AbpModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType); foreach (var plugInModuleType in _abpPlugInManager.PlugInSources.GetAllModules()) { if (modules.AddIfNotContains(plugInModuleType)) { plugInModuleTypes.Add(plugInModuleType); } } return modules;}
哟,可以看到刚进入方法就执行了一个静态方法FindDependedModuleTypesRecursivelyIncludingGivenModule
看到Recursively就清楚了这是一个递归方法... 入参是我们的启动模块类型public static ListFindDependedModuleTypesRecursivelyIncludingGivenModule(Type moduleType){ var list = new List (); AddModuleAndDependenciesRecursively(list, moduleType); list.AddIfNotContains(typeof(AbpKernelModule)); return list;}private static void AddModuleAndDependenciesRecursively(List 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); }}
这里先实例化一个type类型集合对象,保存我们所有的模块类型.然后作为入参传给AddModuleAndDependenciesRecursively
这里的话则是进行一系列的判断,之后先把入参module加入刚才的list集合,然后通过FindDependedModuleTypes寻找其依赖的模块public static ListFindDependedModuleTypes(Type moduleType){ if (!IsAbpModule(moduleType)) { throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName); } var list = new List (); if (moduleType.GetTypeInfo().IsDefined(typeof(DependsOnAttribute), true)) { var dependsOnAttributes = moduleType.GetTypeInfo().GetCustomAttributes(typeof(DependsOnAttribute), true).Cast (); foreach (var dependsOnAttribute in dependsOnAttributes) { foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes) { list.Add(dependedModuleType); } } } return list;}
找到所有的依赖模块后,遍历,递归....这样就把所有的依赖模块都找到了.
然后回到AbpModuleManager执行 RegisterModules(moduleTypes) 注册所有模块(单例)模块的加载顺序排序初步确定
AbpModuleCollection 提供了两个方法,一个是 EnsureKernelModuleToBeFirst
一个是 EnsureStartupModuleToBeLast
public void EnsureKernelModuleToBeFirst(){ EnsureKernelModuleToBeFirst(this);}public void EnsureStartupModuleToBeLast(){ EnsureStartupModuleToBeLast(this, StartupModuleType);}public static void EnsureKernelModuleToBeFirst(Listmodules){ var kernelModuleIndex = modules.FindIndex(m => m.Type == typeof(AbpKernelModule)); if (kernelModuleIndex <= 0) { //It's already the first! return; } var kernelModule = modules[kernelModuleIndex]; modules.RemoveAt(kernelModuleIndex); modules.Insert(0, kernelModule);}public static void EnsureStartupModuleToBeLast(List modules, Type startupModuleType){ var startupModuleIndex = modules.FindIndex(m => m.Type == startupModuleType); if (startupModuleIndex >= modules.Count - 1) { //It's already the last! return; } var startupModule = modules[startupModuleIndex]; modules.RemoveAt(startupModuleIndex); modules.Add(startupModule);}
- EnsureKernelModuleToBeFirst 找到AbpKernelModule的索引.并通过索引获取到AbpKernelModule,先移除之前索引位置,然后从索引0处的位置插入AbpKernelModule,达到AbpKernelModule是处于集合中第一个的位置
- EnsureStartupModuleToBeLast 找到启动模块的索引,并通过索引获取到启动模块,先移除,然后插入到集合中最后一个位置. 所以模块在进行加载的时候,第一个加载的模块一定是核心模块,最后加载的模块肯定是启动模块。
确定每个模块的依赖
AbpModuleInfo
里面有个 public List<AbpModuleInfo> Dependencies { get; }
集合属性,这里面就是存当前模块所有依赖模块的。
SetDependencies
方法中确定的 private void SetDependencies(){ foreach (var moduleInfo in _modules) { moduleInfo.Dependencies.Clear(); //Set dependencies for defined DependsOnAttribute attribute(s). foreach (var dependedModuleType in AbpModule.FindDependedModuleTypes(moduleInfo.Type)) { var dependedModuleInfo = _modules.FirstOrDefault(m => m.Type == dependedModuleType); if (dependedModuleInfo == null) { throw new AbpInitializationException("Could not find a depended module " + dependedModuleType.AssemblyQualifiedName + " for " + moduleInfo.Type.AssemblyQualifiedName); } if ((moduleInfo.Dependencies.FirstOrDefault(dm => dm.Type == dependedModuleType) == null)) { moduleInfo.Dependencies.Add(dependedModuleInfo); } } }}
- 经过CreateModules后AbpModuleCollection中已经存在了所有的依赖,所以这里是直接遍历,寻找当前模块 所依赖的 所有模块,存入当前模块的
public List<AbpModuleInfo> Dependencies { get; }
集合中
确定模块加载顺序排序完全确定
在所有模块基本信息加载完成之后,Abp 并没有在AbpModuleManager的Initialize
里面来进行这个重新排序操作,而是在 StartModules 方法里面来重新排序。
public virtual void Initialize(){ ResolveLogger(); try { RegisterBootstrapper(); IocManager.IocContainer.Install(new AbpCoreInstaller()); IocManager.Resolve().PlugInSources.AddRange(PlugInSources); IocManager.Resolve ().Initialize(); _moduleManager = IocManager.Resolve (); _moduleManager.StartModules(); } catch (Exception ex) { _logger.Fatal(ex.ToString(), ex); throw; }}
- _moduleManager.Initialize(StartupModule);//加载所有模块,确定每个模块所有的依赖模块,确定模块首尾顺序
- _moduleManager.StartModules();//在这里进行模块重新排序
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());}
可以看到StartModules方法中首先进行的就是排序
public ListGetSortedModuleListByDependency(){ var sortedModules = this.SortByDependencies(x => x.Dependencies); EnsureKernelModuleToBeFirst(sortedModules); EnsureStartupModuleToBeLast(sortedModules, StartupModuleType); return sortedModules;}
- SortByDependencies其实这里执行的是一个拓扑排序算法
- 然后还是确定AbpKernelModule为集合首,startupModule为集合尾,到这里,模块顺序就已经全部排序完成.
总结
1.Configure方法中会注册ABP中间件.
2.执行AbpApplicationBuilder的InitializeAbp
扩展方法,从ioc容器中获取abpBootstrapper
3.执行abpBootstrapper的Initialize方法,从Ioc容器中获取AbpModuleManager.
4.执行AbpModuleManager的Initialize方法.
- 根据启动模块的类型初始化一个AbpModuleCollection集合
- 执行LoadAllModules方法
- 执行FindAllModuleTypes方法.递归找到所有模块.
- 执行RegisterModules方法:以单例的形式注册模块到ioc容器
- 执行CreateModules方法:
- 从ioc容器获取模块,设置基本属性(IocManager,Configuration)
- 将模块对象包装成AbpModuleInfo对象,添加进AbpModuleCollection集合中
- 执行AbpModuleCollection的
EnsureKernelModuleToBeFirst
和EnsureStartupModuleToBeLast
,确定集中模块基本首尾顺序(AbpKernelModule索引为0,启动模块索引为最后一位) - 执行SetDependencies方法:遍历AbpModuleCollection,找到当前ModuleInfo的所有依赖模块,添加进moduleInfo.Dependencies属性集合中
5.执行AbpModuleManager的StartModules方法
- 将AbpModuleCollection再次排序(拓扑排序),保证模块执行顺序的正确
- 执行所有模块的PreInitialize方法
- 执行所有模块的Initialize方法
- 执行所有模块的PostInitialize方法