0.引言
ABP提供了構模組化塊和通過組合子產品以建立應用程式的基礎設施。一個子產品可以依賴于另外一個子產品。通常,程式集可以認為是子產品。如果建立多個程式集的應用程式,建議為每個程式集建立子產品定義。
目前,子產品系統主要集中在伺服器,而不是用戶端。
1.子產品定義
子產品是從ABP包中的AbpModule派生的類定義的。比如說開發一個可以用于不同應用程式的部落格子產品(Blog Module)。最簡單的子產品定義如下 :
public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
子產品定義類負責通過依賴注入注冊類,如有必要(可以像上述事例按慣例完成)。它還可以配置應用程式和其它子產品,給應用程式增加新的功能等等。
2.生命周期方法
ABP在程式啟動和關閉時調用子產品一些特定的方法。你可以重寫這些方法以執行某些特定的任務。
ABP按照依賴順序調用這些方法。如果子產品A依賴子產品B,那麼子產品B在子產品A之前初始化。
啟動方法執行準确的順序:PreInitialize-B, PreInitialize-A, Initialize-B, Initialize-A, PostInitialize-B, PostInitialize-A。對于所有依賴關系圖都是如此。關閉方法也是類似的,但順序相反。
相關源碼:子產品啟動時依次執行PreInitialize()、Initialize()、PostInitialize(),子產品關閉時首先Reverse()、然後在逐個子產品Shutdown()。
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());
}
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.");
}
PreInitialize
當應用程式啟動時,首先調用該方法。它是架構和其它子產品初始化之前配置它們的首選方法。
你還可以在該方法中編寫特定的代碼,以便在依賴注入注冊之前運作。例如,如果你建立一個傳統的注冊類,那麼你應在該方法中使用IOCManager.AddConventionalRegisterer方法注冊它們。
Initialize
該方法是依賴注入注冊的地方,通過使用IocManager.RegisterAssemblyByConvention方法完成注冊。如果想定義自定義的依賴注冊,請見後續依賴注入章節。
PostInitialize
該方法在程式啟動的最後調用。在這裡解析依賴是安全的。
Shutdown
該方法在程式關閉時調用。
3.子產品依賴(Module Dependencies)
一個子產品可以依賴于另外的子產品。你可以通過DependsOn特性顯示聲明依賴項,如下代碼:
[DependsOn(typeof(MyBlogCoreModule))]
public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
上述事例代碼中,聲明了MyBlogApplicationModule子產品依賴于MyBlogCoreModule子產品,那麼MyBlogCoreModule子產品應該在MyBlogApplicationModule子產品之前完成初始化。
ABP可以從啟動子產品(start module)開始就遞歸的解析依賴關系,并相應地初始化它們。啟動子產品(start module)是最後進行初始化的子產品。
4.插件子產品
雖然子產品從啟動子產品開始查找并周遊依賴關系,ABP還可以動态加載子產品。AbpBootstrapper類中定義了PlugInSources屬性,該屬性可用于向動态加載的插件子產品添加源。插件源可以是實作IPlugInSource接口的任何類。通過實作FolderPlugInSource類以從指定檔案夾中的程式集擷取插件子產品。
ASP.NET CORE
ABP中ASP.NET CORE子產品在AddAbp擴充方法中定義選項,用于在啟動類中添加插件源:
services.AddAbp<MyStartupModule>(options =>
{
options.PlugInSources.Add(new FolderPlugInSource(@"C:\MyPlugIns"));
});
也可以使用更簡單的文法AddFolder擴充方法:
services.AddAbp<MyStartupModule>(options =>
{
options.PlugInSources.AddFolder(@"C:\MyPlugIns");
});
ASP.NET MVC,Web API
對于傳統的ASP.NET MVC應用程式,可以通過重寫global.asax檔案中Application_Start方法添加插件檔案夾,如下代碼:
public class MvcApplication : AbpWebApplication<MyStartupModule>
{
protected override void Application_Start(object sender, EventArgs e)
{
AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns");
//...
base.Application_Start(sender, e);
}
}
Controllers in PlugIns
如果你的子產品包括MVC或Web API Controolers,ASP.NET不能查找你的控制器。為了克服這個問題,你可以修改global.asax檔案,如下代碼:
using System.Web;
using Abp.PlugIns;
using Abp.Web;
using MyDemoApp.Web;
[assembly: PreApplicationStartMethod(typeof(PreStarter), "Start")]
namespace MyDemoApp.Web
{
public class MvcApplication : AbpWebApplication<MyStartupModule>
{
}
public static class PreStarter
{
public static void Start()
{
//...
MvcApplication.AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns\");
MvcApplication.AbpBootstrapper.PlugInSources.AddToBuildManager();
}
}
}
附加程式集(Additional Assemblies)
預設實作IAssemblyFinder和ITypeFinder接口隻能在這些程式集中查找子產品程式集和類型。也可以在子產品中重寫GetAdditionalAssembliesy方法來包括其它程式集。
自定義子產品方法(Custom Module Methods)
你的子產品還可以擁有自定義的方法,并能在依賴于這個子產品的其它子產品中調用這個方法。假設MyModule2依賴于MyModule1,并想在PreInitialize方法中調用MyModule1子產品中的方法。
public class MyModule1 : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
public void MyModuleMethod1()
{
//this is a custom method of this module
}
}
[DependsOn(typeof(MyModule1))]
public class MyModule2 : AbpModule
{
private readonly MyModule1 _myModule1;
public MyModule2(MyModule1 myModule1)
{
_myModule1 = myModule1;
}
public override void PreInitialize()
{
_myModule1.MyModuleMethod1(); //Call MyModule1's method
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
在上述代碼中,通過構造函數把MyModule1注入到MyModule2,是以MyModule2可以調用MyModule1中的自定義方法,前提是MyModule2依賴于MyModule1。
子產品配置(Module Configuration)
然而自定義方法可以用來配置子產品,建議使用啟動配置(
startup configuration)系統來定義和設定子產品的配置。
子產品生命周期(Module Lifetime)
子產品類自動注冊為單執行個體對象(singleton)。