本篇作為我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
