返回ABP系列html
ABP是「ASP.NET Boilerplate Project (ASP.NET樣板項目)」的簡稱。git
ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程序的新起點,它旨在成爲一個通用的WEB應用程序框架和項目模板。github
ABP的官方網站:http://www.aspnetboilerplate.comapp
ABP官方文檔:http://www.aspnetboilerplate.com/Pages/Documents框架
Github上的開源項目:https://github.com/aspnetboilerplateide
研究過orchard和nopcommerce的都應該知道模塊概念,ABP的模塊也和他們是一回事。實現原理也都同樣:應用程序通常都是先定義模塊接口,而後把模塊編譯的dll放到固定的目錄中(ABP只能放到bin下),應用程序主程序經過加載那些實現了插件接口的dll來實現插件的使用。網站
ABP 框架提供了建立和組裝模塊的基礎,一個模塊可以依賴於另外一個模塊。在一般狀況 下,一個程序集就能夠當作是一個模塊。在 ABP 框架中,一個模塊經過一個類來定義,而這 個類要繼承自 AbpModule。ui
nopcommerce插件實現能夠到:ASP.NET MVC5 插件化機制簡單實現瞭解下。spa
下面的例子,咱們開發一個能夠在多個不一樣應用中被調用MybolgApplication模塊,代碼以下:插件
public class MyBlogApplicationModule : AbpModule //定義 { public override void Initialize() //初始化 { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); //這行代碼的寫法基本上是不變的。它的做用是把當前程序集的特定類或接口註冊到依賴注入容器中。 } }
ABP框架會掃描全部的程序集,而且發現AbpModule類中全部已經導入的全部類,若是你已經建立了包含多個程序集的應用,對於ABP,咱們的建議是爲每個程序集建立一個Module(模塊)。
生命週期:
在一個應用中,abp框架調用了Module模塊的一些指定的方法來進行啓動和關閉模塊的操做。咱們能夠重載這些方法來完成咱們本身的任務。
ABP框架經過依賴關係的順序來調用這些方法,假如:模塊A依賴於模塊B,那麼模塊B要在模塊A以前初始化,模塊啓動的方法順序以下:
一、PreInitialize-B
二、PreInitialize-A
三、Initialize-B
四、Initialize-A
五、PostInitialize-B
六、PostInitialize-A
下面是具體方法的說明:
PreInitialize 預初始化:當應用啓動後,第一次會調用這個方法。在依賴注入註冊以前,你能夠在這個方法中指定本身的特別代碼。舉個例子吧:假如你建立了一個傳統的登記類,那麼你要先註冊這個類(使用IocManager對登記類進行註冊),你能夠註冊事件到IOC容器。
Initialize初始化:在這個方法中通常是來進行依賴注入的註冊,通常咱們經過IocManager.RegisterAssemblyByConvention這個方法來實現。若是你想實現自定義的依賴注入,那麼請參考依賴注入的相關文檔。
PostInitialize提交初始化:最後一個方法,這個方法用來解析依賴關係。
Shutdown關閉:當應用關閉之後,這個方法被調用。
模塊依賴:
Abp框架會自動解析模塊之間的依賴關係,可是咱們仍是建議你經過重載GetDependencies方法來明確的聲明依賴關係。
[DependsOn(typeof(MyBlogCoreModule))]//經過註解來定義依賴關係 public class MyBlogApplicationModule : AbpModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } }
例如上面的代碼,咱們就聲明瞭MyBlogApplicationModule和MyBlogCoreModule的依賴關係(經過屬性attribute),MyBlogApplicationModule這個應用模塊依賴於MyBlogCoreModule核心模塊,而且,MyBlogCoreModule核心模塊會在MyBlogApplicationModule模塊以前進行初始化。
自定義的模塊方法:
咱們本身定義的模塊中可能有方法被其餘依賴於當前模塊的模塊調用,下面的例子,假設模塊2依賴於模塊1,而且想在預初始化的時候調用模塊1的方法。
public class MyModule1 : AbpModule { public override void Initialize() //初始化模塊 { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());//這裏,進行依賴注入的註冊。 } public void MyModuleMethod1() { //這裏寫自定義的方法。 } } [DependsOn(typeof(MyModule1))] public class MyModule2 : AbpModule { private readonly MyModule1 _myModule1; public MyModule2(MyModule1 myModule1) { _myModule1 = myModule1; } public override void PreInitialize() { _myModule1.MyModuleMethod1(); //調用MyModuleMethod1的方法。 } public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } }
就這樣,就把模塊1注入到了模塊2,所以,模塊2就能調用模塊1的方法了。
一、獲取bin下所有dll
/// <summary> /// 獲取bin下所有dll /// </summary> public List<Assembly> GetAllAssemblies() { var allReferencedAssemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList(); var dllFiles = Directory.GetFiles(HttpRuntime.AppDomainAppPath + "bin\\", "*.dll", SearchOption.TopDirectoryOnly).ToList(); return dllFiles.Select(dllFile => allReferencedAssemblies.FirstOrDefault(asm => AssemblyName.ReferenceMatchesDefinition(asm.GetName(), AssemblyName.GetAssemblyName(dllFile)))).Where(locatedAssembly => locatedAssembly != null).ToList(); }
二、判斷是否繼承了AbpModule接口
/// <summary> /// 判斷與AbpModule的Types是否有關 /// </summary> public static bool IsAbpModule(Type type) { return type.IsClass && !type.IsAbstract && typeof(AbpModule).IsAssignableFrom(type); }
三、循環相關的依賴,把他們填在到modules集合中
#region 循環相關的依賴,把他們填在到modules集合中 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)) continue; 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)) return list; var dependsOnAttributes = moduleType.GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>(); list.AddRange(dependsOnAttributes.SelectMany(dependsOnAttribute => dependsOnAttribute.DependedModuleTypes)); return list; } #endregion
四、控制反轉
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Abp.Configuration.Startup; using Abp.Dependency; using Castle.Core.Logging; namespace Abp.Modules { /// <summary> /// This class is used to manage modules. /// </summary> internal class AbpModuleManager : IAbpModuleManager { public ILogger Logger { get; set; } private readonly AbpModuleCollection _modules; private readonly IIocManager _iocManager; private readonly IModuleFinder _moduleFinder; public AbpModuleManager(IIocManager iocManager, IModuleFinder moduleFinder) { _modules = new AbpModuleCollection(); _iocManager = iocManager; _moduleFinder = moduleFinder; Logger = NullLogger.Instance; } /// <summary> /// 初始化模塊 /// </summary> public virtual void InitializeModules() { LoadAll(); //加載全部 var sortedModules = _modules.GetSortedModuleListByDependency(); //初始化Modules的事件 sortedModules.ForEach(module => module.Instance.PreInitialize()); sortedModules.ForEach(module => module.Instance.Initialize()); sortedModules.ForEach(module => module.Instance.PostInitialize()); } /// <summary> /// 關閉模塊 /// </summary> public virtual void ShutdownModules() { var sortedModules = _modules.GetSortedModuleListByDependency(); sortedModules.Reverse(); sortedModules.ForEach(sm => sm.Instance.Shutdown()); } /// <summary> /// /// </summary> private void LoadAll() { Logger.Debug("Loading Abp modules..."); var moduleTypes = AddMissingDependedModules(_moduleFinder.FindAll()); Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total."); //註冊到IOC容器 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中 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); } EnsureKernelModuleToBeFirst(); SetDependencies(); Logger.DebugFormat("{0} modules loaded.", _modules.Count); } /// <summary> /// AbpKernelModule must be the first module /// </summary> private void EnsureKernelModuleToBeFirst() { var kernelModuleIndex = _modules.FindIndex(m => m.Type == typeof (AbpKernelModule)); if (kernelModuleIndex > 0) { var kernelModule = _modules[kernelModuleIndex]; _modules.RemoveAt(kernelModuleIndex); _modules.Insert(0, kernelModule); } } private void SetDependencies() { foreach (var moduleInfo in _modules) { //Set dependencies according to assembly dependency foreach (var referencedAssemblyName in moduleInfo.Assembly.GetReferencedAssemblies()) { var referencedAssembly = Assembly.Load(referencedAssemblyName); var dependedModuleList = _modules.Where(m => m.Assembly == referencedAssembly).ToList(); if (dependedModuleList.Count > 0) { moduleInfo.Dependencies.AddRange(dependedModuleList); } } //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); } } } } 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); } } } } }
AbpModule:模塊抽象類
AbpModuleInfo:模塊信息
AbpModuleCollection:AbpModuleInfo的集合
IAbpModuleManager:模塊管理接口
AbpModuleManager:模塊管理類實現模塊管理接口
IModuleFinder:負責找全部模塊的接口
DefaultModuleFinder:實現IModuleFinder接口
DependsOnAttribute:用來定義ABP模塊依賴其餘模塊
AbpModuleInfo用於封裝AbpModule的基本信息。 AbpModuleCollection則是AbpModuleInfo的集合。
Abp底層框架發現Module是從AbpBootstrapper在執行Initialize方法的時候開始的,該方法會調用IAbpModuleManager實例的InitializeModules方法,這個方法接着調用DefaultModuleFinder的FindAll方法(該方法用於過濾出AbpModule的assembly),而FindAll方法調用TypeFinder獲得全部的assembly. 因此只要你定義的assembly中有一個繼承至AbpModule的類,而且該assembly被引用到你的項目中,那麼這個Module就能夠說會被Abp底層框架集成了。