浅谈模块系统与 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 ...
随机推荐
- pd16.5增加字段备注
EXEC sp_addextendedproperty 'MS_Description', %.q:COLNNAME%, 'user', dbo, 'table', %TABLE%, 'column' ...
- Spring+MVC Controller层接收App端请求的中文参数乱码问题。
在正文之前,说明下Filter的作用: 过滤器顾名思义就是进行过滤的,可以实现代码的定向执行和预处理.通俗点说法filter相当于加油站,request是条路,response是条路,目的地是serv ...
- 小白的CTF学习之路3——二进制数据基础与运算(下)
处理了二进制的整数运算,下面我们来进行令人绝望的浮点数运算 我们先来看一下float事列程序: #include<"stdio.sh"> int main() { fl ...
- vi/vim 三种模式的操作
来源:http://www.runoob.com/linux/linux-vim.html ps:刚刚进入vi/vim 是命令模式 一.命令模式 i 切换到输入模式,以输入字符. x 删除当前光标所在 ...
- CentOS6.8常用服务
service level0 level1 level2 level3 level4 level5 level6 功能 ...
- Atomic in Redis
Since Redis is single-threaded, everything is atomic.
- Missing initializer in const declaration
这是一个 JS 的报错. 如果你要声明一个常量,必须要赋初值.否则就会报错. 比如这样就可以触发这个报错: const foo; 或者 const bar = xxx; 等号右侧由于拼写失误导致的js ...
- Python request库与爬虫框架
Requests库的7个主要方法 requests.request():构造一个请求,支持以下各方法的基础方法 requests.get():获取HTML网页的主要方法,对应于HTTP的GET ...
- 前端基础之 html
---恢复内容开始--- web服务本质 import socket sock=socket.socket() sock.bind(()) sock.listen() where True: conn ...
- linux vsftp 简单配置
查看自己是否安装vsftp rpm -qa | grep vsftp rpm -qa 查看自己已安装的包 过滤vsftp systemctl rsetart vsftpd 重启服务 先关闭防火墙 sy ...