整個 Abp 框架由各個模塊組成,基本上能夠看作一個程序集一個模塊,不排除一個程序集有多個模塊的可能性。能夠看看他官方的這些擴展庫:html
能夠看到每一個項目文件下面都會有一個 xxxModule
的文件,這裏就是存放的模塊文件,一個模塊擁有四個生命週期,分別爲 PreInitialize()
(預加載)、Initialize()
(初始化)、PostInitialize
(初始化完成)、Shutdown()
(銷燬),前三個根據咱們上一篇文章的代碼能夠看到,他是先執行預加載方法,而後執行初始化,最後執行初始化完成方法,銷燬方法則是程序退出的時候執行。app
模塊的主要做用就是在 Abp 框架加載的時候程序集執行初始化操做的,好比說 Abp 庫自身的 AbpKernelModule
模塊,裏面就是各類注入基礎設施,執行初始化操做。框架
能夠看看其中代碼:ide
public sealed class AbpKernelModule : AbpModule { public override void PreInitialize() { // 註冊各類過濾器與基礎組件 IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar()); IocManager.Register<IScopedIocResolver, ScopedIocResolver>(DependencyLifeStyle.Transient); IocManager.Register(typeof(IAmbientScopeProvider<>), typeof(DataContextAmbientScopeProvider<>), DependencyLifeStyle.Transient); AddAuditingSelectors(); AddLocalizationSources(); AddSettingProviders(); AddUnitOfWorkFilters(); ConfigureCaches(); AddIgnoredTypes(); AddMethodParameterValidators(); } public override void Initialize() { // 這裏是執行替換服務的 Action,Abp 容許用戶在預加載操做替換基礎設施的服務 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 }); } public override void PostInitialize() { // 權限管理器等初始化才作 RegisterMissingComponents(); IocManager.Resolve<SettingDefinitionManager>().Initialize(); IocManager.Resolve<FeatureManager>().Initialize(); IocManager.Resolve<PermissionManager>().Initialize(); IocManager.Resolve<LocalizationManager>().Initialize(); IocManager.Resolve<NotificationDefinitionManager>().Initialize(); IocManager.Resolve<NavigationManager>().Initialize(); if (Configuration.BackgroundJobs.IsJobExecutionEnabled) { var workerManager = IocManager.Resolve<IBackgroundWorkerManager>(); workerManager.Start(); workerManager.Add(IocManager.Resolve<IBackgroundJobManager>()); } } public override void Shutdown() { // 中止全部後臺工做者 if (Configuration.BackgroundJobs.IsJobExecutionEnabled) { IocManager.Resolve<IBackgroundWorkerManager>().StopAndWaitToStop(); } } }
咱們定義好模塊以後,Abp 如何發現咱們的模塊呢?this
在最外部,咱們使用 services.AddAbp<TStartModule>()
的時候,就傳入了啓動模塊類型。code
在以前 AbpBootstrapper
的 Initialize()
初始化方法當中經過調用 AbpModuleManager.Initialize(Type startupModule)
方法來初始化,在其內部能夠看到:orm
public virtual void Initialize(Type startupModule) { _modules = new AbpModuleCollection(startupModule); LoadAllModules(); }
這裏經過傳入啓動模塊來初始化 AboModuleCollection
類。htm
internal class AbpModuleCollection : List<AbpModuleInfo> { public Type StartupModuleType { get; } public AbpModuleCollection(Type startupModuleType) { StartupModuleType = startupModuleType; } // 其餘代碼 }
初始化完成以後,繼續調用 LoadAllModules()
方法,這裏就開始加載模塊了。對象
private void LoadAllModules() { Logger.Debug("Loading Abp modules..."); List<Type> plugInModuleTypes; // 發現全部 Abp 模塊 var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList(); Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total."); // 註冊 Abp 模塊 RegisterModules(moduleTypes); // 建立模塊對應的 AbpModuleInfo 包裝類 CreateModules(moduleTypes, plugInModuleTypes); // 將核心模塊放在第一位初始化 _modules.EnsureKernelModuleToBeFirst(); // 將啓動模塊放在最後一位進行初始化 _modules.EnsureStartupModuleToBeLast(); // 設置每一個 ModuleInfo 的依賴關係 SetDependencies(); Logger.DebugFormat("{0} modules loaded.", _modules.Count); }
繼續跳轉,來到內部 FindAllModuleTypes()
方法,在這個方法裏面咱們能夠看到他調用了 AbpModule
的一個靜態方法來根據其啓動模塊,以後經過啓動模塊上面的 DependsOnAttribute
特性來遞歸找到它全部的依賴模塊。blog
private List<Type> FindAllModuleTypes(out List<Type> plugInModuleTypes) { plugInModuleTypes = new List<Type>(); var modules = AbpModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType); // 其餘代碼 return modules; }
找到模塊以後,在 RegisterModules()
裏面經過 IocManager
的註冊方法,將全部模塊都注入到 Ioc 容器當中,注意這裏註冊的全部的 Abp 模塊都是單例對象。
在 LoadAllModules()
方法裏面,經過 CreateModules()
方法來包裝好 ModuleInfo 類而且將其放在以前初始化完成的 AbpModuleCollection
對象 _modules
裏面。
private void CreateModules(ICollection<Type> moduleTypes, List<Type> plugInModuleTypes) { foreach (var moduleType in moduleTypes) { // 解析剛纔在 RegisterModules 裏面註冊的單例模塊對象 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>(); // 包裝成爲 ModuleInfo var moduleInfo = new AbpModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType)); _modules.Add(moduleInfo); if (moduleType == _modules.StartupModuleType) { StartupModule = moduleInfo; } Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName); } }
在每一個 ModuleInfo
對象內部都存放有該模塊的模塊類型信息,以及他的單例對象實例。
模塊在進行加載的時候,第一個加載的模塊必定是從核心模塊,最後加載的模塊確定是啓動模塊。因此,這裏的 AbpModuleCollection
提供了兩個方法,一個是 EnsureKernelModuleToBeFirst()
,一個是 EnsureStartupModuleToBeLast()
。這兩個方法的做用第一個就是將 AbpKernelModule
放在第一位,第二個就是將啓動模塊放在集合的末尾。
public static void EnsureKernelModuleToBeFirst(List<AbpModuleInfo> modules) { var kernelModuleIndex = modules.FindIndex(m => m.Type == typeof(AbpKernelModule)); if (kernelModuleIndex <= 0) { // 若是 AbpKernelModule 位於首位則不移動位置 return; } var kernelModule = modules[kernelModuleIndex]; modules.RemoveAt(kernelModuleIndex); modules.Insert(0, kernelModule); }
public static void EnsureStartupModuleToBeLast(List<AbpModuleInfo> modules, Type startupModuleType) { var startupModuleIndex = modules.FindIndex(m => m.Type == startupModuleType); if (startupModuleIndex >= modules.Count - 1) { // 若是啓動模塊位於尾部則則不移動位置 return; } var startupModule = modules[startupModuleIndex]; modules.RemoveAt(startupModuleIndex); modules.Add(startupModule); }
以前這些步驟已經將咱們程序所使用到的全部模塊已經加載完成,而且進行了一個基本的排序操做,以確保咱們的模塊加載順序沒有大問題。可是僅僅這樣是不夠的, 咱們還須要確保咱們依賴的模塊比被引用的模塊要先加載,這個時候就須要肯定每一個模塊的依賴關係,而且根據這個依賴關係再次進行排序。
由於咱們以前爲每一個模塊包裝了一個 ModuleInfo
實例,在 ModuleInfo
內部還有一個屬性,叫作:
/// <summary> /// All dependent modules of this module. /// </summary> public List<AbpModuleInfo> Dependencies { get; }
因此,在 LoadAllModules()
方法裏面還調用了一個方法,叫作 SetDependencies()
,這個方法也是很簡單的,遍歷已經加載完成的 _modules
集合,在裏面再根據 AbpModule
提供的 FindDependedModuleTypes()
方法來獲取該模塊的全部依賴模塊類型。找到以後,在 AbpModuleInfo
集合裏面查找對應的依賴模塊的的 ModuleInfo
信息添加到目標模塊的 Dependencies 集合內部。
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); } } } }
在全部基本信息加載完成以後,Abp 並無在 AbpModuleManager
的 Initialize()
裏面來進行這個從新排序操做,而是在 StartModules()
方法裏面來從新排序。
在 StartModules()
經過 AbpModuleCollection
提供的 GetSortedModuleListByDependency()
方法來根據依賴項從新進行了一次排序。
public List<AbpModuleInfo> GetSortedModuleListByDependency() { var sortedModules = this.SortByDependencies(x => x.Dependencies); EnsureKernelModuleToBeFirst(sortedModules); EnsureStartupModuleToBeLast(sortedModules, StartupModuleType); return sortedModules; }
這裏使用的是存放在 \Abp\src\Abp\Collections\Extensions\ListExtensions.cs
的一個擴展方法 List<T> SortByDependencies<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependencies)
,他是針對 List<T>
集合實現的一種拓撲排序。
排序以後的結果就是按照依賴關係來存放的一個集合,以後經過 List 的 Foreach 方法循環調用其三個生命週期方法便可。
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()); }
/// <summary> /// Extension methods for <see cref="IList{T}"/>. /// </summary> public static class ListExtensions { /// <summary> /// Sort a list by a topological sorting, which consider their dependencies /// </summary> /// <typeparam name="T">The type of the members of values.</typeparam> /// <param name="source">A list of objects to sort</param> /// <param name="getDependencies">Function to resolve the dependencies</param> /// <returns></returns> public static List<T> SortByDependencies<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependencies) { /* See: http://www.codeproject.com/Articles/869059/Topological-sorting-in-Csharp * http://en.wikipedia.org/wiki/Topological_sorting */ var sorted = new List<T>(); var visited = new Dictionary<T, bool>(); foreach (var item in source) { SortByDependenciesVisit(item, getDependencies, sorted, visited); } return sorted; } /// <summary> /// /// </summary> /// <typeparam name="T">The type of the members of values.</typeparam> /// <param name="item">Item to resolve</param> /// <param name="getDependencies">Function to resolve the dependencies</param> /// <param name="sorted">List with the sortet items</param> /// <param name="visited">Dictionary with the visited items</param> private static void SortByDependenciesVisit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted, Dictionary<T, bool> visited) { bool inProcess; var alreadyVisited = visited.TryGetValue(item, out inProcess); if (alreadyVisited) { if (inProcess) { throw new ArgumentException("Cyclic dependency found! Item: " + item); } } else { visited[item] = true; var dependencies = getDependencies(item); if (dependencies != null) { foreach (var dependency in dependencies) { SortByDependenciesVisit(dependency, getDependencies, sorted, visited); } } visited[item] = false; sorted.Add(item); } } }
後面專門寫文章講解一下拓撲排序,這裏貼上代碼,後面會改成文章連接的。
貼上詳解連接:
http://www.javashuo.com/article/p-pvxcyudw-hy.html
本篇文章主要針對模塊系統進行了一個較爲詳細地分析,後面將會講解 Abp 依賴注入相關的代碼,若是你以爲對你有用請點個贊,謝謝。