本篇作为我ABP介绍的第三篇文章,这次想讲下模块的,ABP文档已经有模块这方面的介绍,但是它只讲到如何使用模块,我想详细讲解下它模块的设计思路。

ABP 框架提供了创建和组装模块的基础,一个模块能够依赖于另一个模块。在通常情况 下,一个程序集就可以看成是一个模块。在 ABP 框架中,一个模块通过一个类来定义,而这 个类要继承自 AbpModule。

其实它的设计思路很简单:

1、加载bin目录下的所有dll

    public class WebAssemblyFinder : IAssemblyFinder
{
/// <summary>
/// This return all assemblies in bin folder of the web application.
/// </summary>
/// <returns>List of assemblies</returns>
public List<Assembly> GetAllAssemblies()
{
var assembliesInBinFolder = new List<Assembly>(); var allReferencedAssemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();
var dllFiles = Directory.GetFiles(HttpRuntime.AppDomainAppPath + "bin\\", "*.dll", SearchOption.TopDirectoryOnly).ToList(); foreach (string dllFile in dllFiles)
{
var locatedAssembly = allReferencedAssemblies.FirstOrDefault(asm => AssemblyName.ReferenceMatchesDefinition(asm.GetName(), AssemblyName.GetAssemblyName(dllFile)));
if (locatedAssembly != null)
{
assembliesInBinFolder.Add(locatedAssembly);
}
} return assembliesInBinFolder;
}
}

2、循环判断获取所有与AbpModule的Types有关

        public static bool IsAbpModule(Type type)
{
return
type.IsClass &&
!type.IsAbstract &&
typeof(AbpModule).IsAssignableFrom(type);
}

并递归获取没有只在所有的DependsOnAttribute,把他们填在到modules集合中(请详细看AbpModule.FindDependedModuleTypes方法)

        private static ICollection<Type> AddMissingDependedModules(ICollection<Type> allModules)
{
var initialModules = allModules.ToList();
foreach (var module in initialModules)
{
FillDependedModules(module, allModules);
} return allModules;
} private static void FillDependedModules(Type module, ICollection<Type> allModules)
{
foreach (var dependedModule in AbpModule.FindDependedModuleTypes(module))
{
if (!allModules.Contains(dependedModule))
{
allModules.Add(dependedModule);
FillDependedModules(dependedModule, allModules);
}
}
}
        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.IsDefined(typeof(DependsOnAttribute), true))
{
var dependsOnAttributes = moduleType.GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>();
foreach (var dependsOnAttribute in dependsOnAttributes)
{
foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes)
{
list.Add(dependedModuleType);
}
}
} return list;
}

所有关于模块的重要代码都在AbpModuleManager中,在上面我们已经加载了所有的模块的类型,那么ABP到底有多少个Modules呢

在我下载的Demo中包含了十三个Module,都继承字AbpModule类

3、既然我得到了所有的moduleTypes了,那么我就通过Castle Windsor循环注册了,并反转

        private void LoadAll()
{
Logger.Debug("Loading Abp modules...");
//通过bin加载所有的module集合
var moduleTypes = AddMissingDependedModules(_moduleFinder.FindAll());
Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total."); //通过castle windsor注册所有的模块 Register to IOC container.
foreach (var moduleType in moduleTypes)
{
if (!AbpModule.IsAbpModule(moduleType))
{
throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
} if (!_iocManager.IsRegistered(moduleType))
{
_iocManager.Register(moduleType);
}
} //模块反转并添加到_modules中 Add to module collection
foreach (var moduleType in moduleTypes)
{
var moduleObject = (AbpModule)_iocManager.Resolve(moduleType); moduleObject.IocManager = _iocManager;
moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>(); _modules.Add(new AbpModuleInfo(moduleObject)); Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
} //确保AbpKernelModule是_modules中第一个module,AbpKernelModule must be the first module
var startupModuleIndex = _modules.FindIndex(m => m.Type == typeof(AbpKernelModule));
if (startupModuleIndex > 0)
{
var startupModule = _modules[startupModuleIndex];
_modules.RemoveAt(startupModuleIndex);
_modules.Insert(0, startupModule);
} SetDependencies(); Logger.DebugFormat("{0} modules loaded.", _modules.Count);
}

上面代码有注释,详细请看注释

4、就是初始化所有模块的事件,早AbpModule中作者定义了三个事件,在实践应用在我们会依次执行下面三个方法

        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()
{ }

在一个应用中,ABP 框架调用了 Module 模块的一些指定的方法来进行启动和关闭模块的 操作。我们可以重载这些方法来完成我们自己的任务。 ABP 框架通过依赖关系的顺序来调用这些方法,

假如:模块 A 依赖于模块 B,那么模块 B 要在模块 A 之前初始化,模块启动的方法顺序如下:

1) PreInitialize-B

2) PreInitialize-A

3) Initialize-B

4) Initialize-A

5) PostInitialize-B

6) PostInitialize-A

那么我们是怎么执行上面的方法的呢,方案在AbpModuleManager的InitializeModules方法中

        public virtual void InitializeModules()
{
LoadAll(); var sortedModules = _modules.GetSortedModuleListByDependency(); sortedModules.ForEach(module => module.Instance.PreInitialize());
sortedModules.ForEach(module => module.Instance.Initialize());
sortedModules.ForEach(module => module.Instance.PostInitialize());
}

那么我们在自定义模块的时候是要重写上面三个方法的,有点像管道的事件,我们会依次执行这些事件,现在我们随便看个AbpEntityFrameworkModule模块它重写了其中两个

       public override void PreInitialize()
{
IocManager.AddConventionalRegistrar(new EntityFrameworkConventionalRegisterer());
} public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); IocManager.IocContainer.Register(
Component.For(typeof (IDbContextProvider<>))
.ImplementedBy(typeof (UnitOfWorkDbContextProvider<>))
.LifestyleTransient()
); RegisterGenericRepositories();
}

一般的我们都要在Initialize方法中加上这句IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); 也就是注册当前程序集,IOC初始化用的哦,好了,至此终于把ABP模块的思路讲完啦,大家可以配合ABP的文档的相关章节进行研究,希望对初学者有帮助。

参考文章:

https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese

最新文章

  1. CLR VIA C# 学习笔记
  2. javascript基础语法——表达式
  3. Exploit利用学习1:MS09-001
  4. 用AutoHotKey彻底解决“Ctrl键+鼠标滚动”时的缩放问题
  5. 20160129.CCPP体系详解(0008天)
  6. 浅谈“be practical and realistic”
  7. IE8浏览器跨域接口访问异常的解决办法
  8. Oracle批量加注释,并生成html
  9. Hololens文件读写
  10. ABP架构解析
  11. GEF开发eclipse插件,多页编辑器实现delete功能
  12. Python 中关于Random的使用方法
  13. Exp5 MSF基础应用 20164303景圣
  14. Ettercap 实施中间人攻击
  15. Vc数据库编程基础MySql数据库的表增删改查数据
  16. Windows命令查看文件MD5,SHA1,SHA256 文件校验
  17. 23.HashMap
  18. 雷林鹏分享:XMLHttpRequest 对象
  19. Thymeleaf(Java模板引擎)
  20. 2.6.33中关于at91sam9260的i2c controller驱动的问题

热门文章

  1. 不知道张(zhāng)雱(pāng)是谁?你out了!
  2. js array queue (队列)
  3. for 循环打印图形
  4. Java三大框架 介绍
  5. OpenCASCADE Curve Length Calculation
  6. 深入学习jQuery事件对象
  7. EntityFramework之孩子删除(四)(你以为你真的懂了?)
  8. 在ASP.NET MVC的Action中直接接受客户端发送过来的HTML内容片段
  9. 使用纯前端JavaScript 实现Excel IO
  10. 利用SkyDrive Pro 迅速批量下载SharePoint Server 上已上传的文件