浅谈模块系统与 ABP 框架初始化
在 ABP 框架当中所有库以及项目都是以模块的形式存在,所有模块都是继承自AbpModule 这个抽象基类,每个模块都拥有四个生命周期。分别是:
- PreInitialze();
- Initialize();
- PostInitialize():
- ShutDown();
AddAbp<TStartipModule>()
在初始化 ABP 框架的时候,通过 services.AddAbp<AbpTestMulitPageWebHostModule>方法将启动模块作为泛型参数传入到 AddAbp 当中。
之后根据传入的启动模块,初始化 AbpBootstrapper,在 AbpBootstrapper 初始化的时候执行拦截器注册等操作。
之后配置 Asp Net Core 相关服务,替换控制器、视图组件、过滤器等默认实现,改用ABP 框架的实现,并且将 Ioc 容器替换为 CastleWindsor。
app.UseAbp()
之前的 AddAbp 仅仅是在 ConfigureService 注入服务,紧接着就会在 Configure方法启用 Abp 中间件。
private static void InitializeAbp(IApplicationBuilder app)
{
var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
abpBootstrapper.Initialize();
}
可以看到在初始化 ABP 的时候,实际上是从 Ioc 容器中解析出 AbpBootStrapper 调用它的初始化方法。
AbpBootStrapper.Initialize()
public virtual void Initialize()
{
ResolveLogger();
try
{
RegisterBootstrapper();
IocManager.IocContainer.Install(new AbpCoreInstaller());
IocManager.Resolve<AbpPlugInManager>().PlugInSources.AddRange(PlugInSources);
IocManager.Resolve<AbpStartupConfiguration>().Initialize();
_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);
_moduleManager.StartModules();
}
catch (Exception ex)
{
_logger.Fatal(ex.ToString(), ex);
throw;
}
}
首先注册了日志组件,之后再次注册了 AbpBootStarpper,可能是防止 Ioc 容器没有注册成功吧。
然后调用了 Castle 的 Install 方法,将一些核心组件通过安装器注入到容器当中。
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IUnitOfWorkDefaultOptions, UnitOfWorkDefaultOptions>().ImplementedBy<UnitOfWorkDefaultOptions>().LifestyleSingleton(),
Component.For<INavigationConfiguration, NavigationConfiguration>().ImplementedBy<NavigationConfiguration>().LifestyleSingleton(),
Component.For<ILocalizationConfiguration, LocalizationConfiguration>().ImplementedBy<LocalizationConfiguration>().LifestyleSingleton(),
Component.For<IAuthorizationConfiguration, AuthorizationConfiguration>().ImplementedBy<AuthorizationConfiguration>().LifestyleSingleton(),
Component.For<IValidationConfiguration, ValidationConfiguration>().ImplementedBy<ValidationConfiguration>().LifestyleSingleton(),
Component.For<IFeatureConfiguration, FeatureConfiguration>().ImplementedBy<FeatureConfiguration>().LifestyleSingleton(),
Component.For<ISettingsConfiguration, SettingsConfiguration>().ImplementedBy<SettingsConfiguration>().LifestyleSingleton(),
Component.For<IModuleConfigurations, ModuleConfigurations>().ImplementedBy<ModuleConfigurations>().LifestyleSingleton(),
Component.For<IEventBusConfiguration, EventBusConfiguration>().ImplementedBy<EventBusConfiguration>().LifestyleSingleton(),
Component.For<IMultiTenancyConfig, MultiTenancyConfig>().ImplementedBy<MultiTenancyConfig>().LifestyleSingleton(),
Component.For<ICachingConfiguration, CachingConfiguration>().ImplementedBy<CachingConfiguration>().LifestyleSingleton(),
Component.For<IAuditingConfiguration, AuditingConfiguration>().ImplementedBy<AuditingConfiguration>().LifestyleSingleton(),
Component.For<IBackgroundJobConfiguration, BackgroundJobConfiguration>().ImplementedBy<BackgroundJobConfiguration>().LifestyleSingleton(),
Component.For<INotificationConfiguration, NotificationConfiguration>().ImplementedBy<NotificationConfiguration>().LifestyleSingleton(),
Component.For<IEmbeddedResourcesConfiguration, EmbeddedResourcesConfiguration>().ImplementedBy<EmbeddedResourcesConfiguration>().LifestyleSingleton(),
Component.For<IAbpStartupConfiguration, AbpStartupConfiguration>().ImplementedBy<AbpStartupConfiguration>().LifestyleSingleton(),
Component.For<IEntityHistoryConfiguration, EntityHistoryConfiguration>().ImplementedBy<EntityHistoryConfiguration>().LifestyleSingleton(),
Component.For<ITypeFinder, TypeFinder>().ImplementedBy<TypeFinder>().LifestyleSingleton(),
Component.For<IAbpPlugInManager, AbpPlugInManager>().ImplementedBy<AbpPlugInManager>().LifestyleSingleton(),
Component.For<IAbpModuleManager, AbpModuleManager>().ImplementedBy<AbpModuleManager>().LifestyleSingleton(),
Component.For<IAssemblyFinder, AbpAssemblyFinder>().ImplementedBy<AbpAssemblyFinder>().LifestyleSingleton(),
Component.For<ILocalizationManager, LocalizationManager>().ImplementedBy<LocalizationManager>().LifestyleSingleton()
);
}
下一步解析 AbpBootStrapperConfiguration 初始化所有核心模块的配置项。
之后就是最重要的初始化模块操作了。
private void LoadAllModules()
{
Logger.Debug("Loading Abp modules...");
List<Type> plugInModuleTypes;
// 查找所有模块,封装到 List<Type> 容器
var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList();
Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");
// 注册模块到 Ioc 容器
RegisterModules(moduleTypes);
CreateModules(moduleTypes, plugInModuleTypes);
_modules.EnsureKernelModuleToBeFirst();
_modules.EnsureStartupModuleToBeLast();
SetDependencies();
Logger.DebugFormat("{0} modules loaded.", _modules.Count);
}
FindAllModuleTypes
private List<Type> FindAllModuleTypes(out List<Type> plugInModuleTypes)
{
plugInModuleTypes = new List<Type>();
// 内部根据[DependsOn]特性来,递归获取所有模块
var modules = AbpModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType);
foreach (var plugInModuleType in _abpPlugInManager.PlugInSources.GetAllModules())
{
if (modules.AddIfNotContains(plugInModuleType))
{
plugInModuleTypes.Add(plugInModuleType);
}
}
return modules;
}
CreateModules
private void CreateModules(ICollection<Type> moduleTypes, List<Type> plugInModuleTypes)
{
foreach (var moduleType in moduleTypes)
{
var moduleObject = _iocManager.Resolve(moduleType) as AbpModule;
if (moduleObject == null)
{
throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
}
moduleObject.IocManager = _iocManager;
moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>();
// 将模块类型封装到 AbpModule 当中
var moduleInfo = new AbpModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType));
_modules.Add(moduleInfo);
// 设置启动模块
if (moduleType == _modules.StartupModuleType)
{
StartupModule = moduleInfo;
}
Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
}
}
总的来说 CreateModules 的作用就是将之前获取到的模块类型数据再封装为 AbpModuleInfo对象。在 ModuleInfo 对象内部还包括了这个模块所依赖的模块信息。
构建好所有模块的 ModuleInfo 信息之后,对这个 List<ModuleInfo> 进行排序,将启动模块放在最后,将核心模块放在第一位,具体操作可以参考 _modules.EnsureKernelModuleToBeFirst(); 和_modules.EnsureStartupModuleToBeLast(); 这两个方法。这么做是因为要确保最核心的模块第一位初始化,然后再依次初始化他的子模块。因为是启动模块,所以他是这个依赖树的最低端,留在最后初始化。
SetDependencies
遍历 List<ModuleType> 设置每个模块的依赖模块。回到最开始的地方,这里仅仅是初始化模块,之后调用了 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());
}
启动模块的时候,先按照依赖项来排序,顺序是 Kernal->Module1->Module->2->StartModule。之后从 PreInitialize->Initialize->PostInitialize 这样遍历执行。
执行完之后所有模块就已经初始化完成了。
这里可以看到并没有 ShutDown 方法执行,ShutDown 执行的时机是在 AbpBootStrapper 被释放的时候,进行调用。
public virtual void ShutdownModules()
{
Logger.Debug("Shutting down has been started");
var sortedModules = _modules.GetSortedModuleListByDependency();
sortedModules.Reverse();
sortedModules.ForEach(sm => sm.Instance.Shutdown());
Logger.Debug("Shutting down completed.");
}
不过执行 ShutDown 方法的时候,会将模块列表反转,按照 Start->Module2->Module1->Kernal 这样来关闭。
模块是 ABP 框架的基础单元,在 ABP 的实现当中模块大部分被当做功能库的形式存在。如果你要使用 ABP 框架的话,必须要定义一个启动模块,不然其他功能是无法正常进行初始化的。
AbpModule
public abstract class AbpModule
{
/// <summary>
/// Gets a reference to the IOC manager.
/// </summary>
protected internal IIocManager IocManager { get; internal set; }
/// <summary>
/// Gets a reference to the ABP configuration.
/// </summary>
protected internal IAbpStartupConfiguration Configuration { get; internal set; }
/// <summary>
/// Gets or sets the logger.
/// </summary>
public ILogger Logger { get; set; }
protected AbpModule()
{
Logger = NullLogger.Instance;
}
/// <summary>
/// This is the first event called on application startup.
/// Codes can be placed here to run before dependency injection registrations.
/// </summary>
public virtual void PreInitialize()
{
}
/// <summary>
/// This method is used to register dependencies for this module.
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// This method is called lastly on application startup.
/// </summary>
public virtual void PostInitialize()
{
}
/// <summary>
/// This method is called when the application is being shutdown.
/// </summary>
public virtual void Shutdown()
{
}
public virtual Assembly[] GetAdditionalAssemblies()
{
return new Assembly[0];
}
/// <summary>
/// Checks if given type is an Abp module class.
/// </summary>
/// <param name="type">Type to check</param>
public static bool IsAbpModule(Type type)
{
var typeInfo = type.GetTypeInfo();
return
typeInfo.IsClass &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
typeof(AbpModule).IsAssignableFrom(type);
}
/// <summary>
/// Finds direct depended modules of a module (excluding given module).
/// </summary>
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);
}
}
}
在 Abp 模块当中会为你注入一些必须的设施,比如 Ioc 容器,模块配置集合,日志记录器等。
如果想知道模块如何编写,可以参考 ABP 原有的功能模块实现。
浅谈模块系统与 ABP 框架初始化的更多相关文章
- [ABP]浅谈模块系统与 ABP 框架初始化
在 ABP 框架当中所有库以及项目都是以模块的形式存在,所有模块都是继承自AbpModule 这个抽象基类,每个模块都拥有四个生命周期.分别是: PreInitialze(); Initialize( ...
- [原创] 浅谈ETL系统架构如何测试?
[原创] 浅谈ETL系统架构如何测试? 来新公司已入职3个月时间,由于公司所处于互联网基金行业,基金天然固有特点,基金业务复杂,基金数据信息众多,基金经理众多等,所以大家可想一下,基民要想赚钱真不容易 ...
- 浅谈Python Web的五大框架
说到Web Framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界.各种micro-framework.framework不可胜数. 尽管还有一大脚本语言PHP也有 ...
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6627260 在前面一篇文章浅谈Service ...
- (转)浅谈 Linux 系统中的 SNMP Trap
原文:https://www.ibm.com/developerworks/cn/linux/l-cn-snmp/index.html 简介 本文讲解 SNMP Trap,在介绍 Trap 概念之前, ...
- 浅谈Storm流式处理框架(转)
Hadoop的高吞吐,海量数据处理的能力使得人们可以方便地处理海量数据.但是,Hadoop的缺点也和它的优点同样鲜明——延迟大,响应缓慢,运维复杂. 有需求也就有创造,在Hadoop基本奠定了大数据霸 ...
- 浅谈OA系统与Portal门户的区别
随着社会信息化的发展与进步,OA办公自动化软件打破了传统复杂的办公方式,使各个行业实现了高效的无纸化办公.由此一来OA快速成长为继财务软件.ERP软件之后的第三大管理软件.随着企业信息化系统的不断增多 ...
- 浅谈Storm流式处理框架
Hadoop的高吞吐,海量数据处理的能力使得人们可以方便地处理海量数据.但是,Hadoop的缺点也和它的优点同样鲜明——延迟大,响应缓慢,运维复杂. 有需求也就有创造,在Hadoop基本奠定了大数据霸 ...
- 浅谈Android系统移植、Linux设备驱动
一.Android系统架构 第一层:Linux内核 包括驱动程序,管理内存.进程.电源等资源的程序 第二层:C/C++代码库 包括Linux的.so文件以及嵌入到APK程序中的NDK代码 第三层:An ...
随机推荐
- 第二阶段第四次spring会议
昨天我将对软件添加了初始页面. 今天我将对软件加上显示时间. try { SkinListBoxItem rt = new SkinListBoxItem(InputForm("请输入&qu ...
- Vmware Workstation - linux系统下 VmTools 安装
程序版本 : VMware® Workstation 14 Pro 系统环境 : win10 64位下 ubuntu-14.04.5-desktop-amd64 问题:在运行linux系统过程中,de ...
- Scikit-learn 安装
Scikit-Learn 3 pip 安装 如果安装了Python,没有安装pip,使用Windows + R,输入cmd,回车打开命令行,输入 python -m pip install -U pi ...
- Naïve Media Player
我的GitHub链接:https://github.com/Joyce45/hwt 一.播放器?怎么做? 提到播放器,首先想到的就是XAML控件库里的MediaElement,于是我又大致阅读了一下该 ...
- 对int数组排序
// 排序-->小到大1 public void sortArray(int[] targetArr) { long t = System.currentTimeMi ...
- Visual Studio Code 学习记录
Visual Studio Code的官方文档可以学到很多知识,不只是vs code的用法,包括一些语言的入门 和一些概念等等.很好的文档. ※,user.settings.json中的一些配置说明: ...
- go 切片的创建方式
切片的创建方式现知道的有下面几种方式,切片为指针类型,从数组中得到的切片修改元素值时,原数组也会发生变化(数组为非指针类型) package main import "fmt" f ...
- PowerShell工作流学习-6-向脚本工作流添加检查点
关键点: a)检查点是工作流当前状态的快照,其中包括变量的当前值以及在该点生成的任何输出,这些信息保存在磁盘. b)检查点数据保存在托管工作流会话的计算机的硬盘上的用户配置文件中. c)当工作流通用参 ...
- 高斯混合模型的EM算法
高斯混合模型的EM算法 混合高斯模型 高斯混合模型的概率分布可以写成多个高斯分布的线形叠加,即 \[ p(\mathbf x) = \sum_{k=1}^{K}\pi_k\mathcal N(\mat ...
- cv2.cvtColor Unsupported depth of input image
源代码 import cv2 import numpy as ny img = ny.zeros( ( 3 , 3 )) img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) ...