通俗理解ABP中的模組Module
網上有不少文章說ABP的模組,有的直接翻譯自官網介紹,有的分析Modlue的源程式碼,有的寫一通程式碼,沒什麼注釋,很少有能通俗說清的。那麼,有兩個問題:1.ABP中的模組到底是什麼?2.搞這個東西是幹嘛用的?難道是吃撐了沒事做?下面我們來如何通俗回答這兩個問題。
第一個問題:ABP中的模組到底是什麼?
通俗的理解,這個東西就相當於程式集,你開發的項目不是有很多個類庫嗎?或者會有很多個所謂的「項目型」的程式集嗎?如下圖所示:
裡面不是有一堆東西嗎?例如:AbpCompanyName.AbpProjectName.Application,AbpCompanyName.ProjectName.TestModule等等一堆東西,這些東西就是模組,也就是程式集。這並沒有什麼好稀奇,也沒什麼好神秘的,就是Assembly而已,只不過:在ABP中,我們要讓這個程式集成為一個Module模組,需要在這個程式集里單獨定義一個繼承於AbpModule的類,例如在我的AbpCompanyName.ProjectName.TestModule里,我就定義一個繼承於AbpModule的AbpProjectNameTestModule類,並在它的 Initialize()方法里鼓搗一句註冊的方法: IocManager.RegisterAssemblyByConvention(typeof(AbpProjectNameTestModule).Assembly)即可。
如下面程式碼所示:


[DependsOn(typeof(AbpProjectName.AbpProjectNameApplicationModule))] public class AbpProjectNameTestModule:AbpModule { private string _initStr = string.Empty; public string InitStr { get { return _initStr; } set { _initStr = value; }} public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(AbpProjectNameTestModule).Assembly); //base.Initialize(); } public AbpProjectNameTestModule() { //Init _initStr = "AbpProjectNameTestModule() constructor init"; Console.WriteLine(_initStr); } }
View Code
請忽略其他幾個次要的程式碼,只關注Initialize方法即可。
第二個問題:搞這個東西是幹嘛用的?
既然這玩意就是程式集,那麼還要費盡心思搞這個模組幹嘛?豈不多此一舉嗎?難道讓我吃飽了沒事做嗎?當然你可以不用,但用了有什麼好處呢?如果我的項目有多個程式集,其中有一個依賴於其他幾個程式集,如果這個項目一成不變倒沒什麼問題。但是如果有變,要替換其中依賴的一個或者幾個程式集呢?那麼問題就來了,凡是這個項目中有引用到的這些依賴程式集,都要一一替換,所以這個時候,就該使用ABP的模組了,它用來解決模組(或者叫程式集)的依賴問題。
ABP中使用模組依賴來解決這個問題,如果一個模組需要依賴於其他的模組,我們只需要在這個模組的上面寫上屬性DependsOn(XXXX模組)即可.例如我這裡有一個叫做AbpProjectNameWebModule的模組,它依賴於AbpProjectNameApplicationModule,AbpProjectNameEntityFrameworkCoreModule,AbpAspNetCoreModule和AbpProjectNameTestModule,我們只需要在AbpProjectNameWebModule的頭部加上這句即可:
[DependsOn(
typeof(AbpProjectNameApplicationModule),
typeof(AbpProjectNameEntityFrameworkCoreModule),
typeof(AbpAspNetCoreModule),
typeof(AbpProjectNameTestModule)
)]
程式碼如下所示:


[DependsOn( typeof(AbpProjectNameApplicationModule), typeof(AbpProjectNameEntityFrameworkCoreModule), typeof(AbpAspNetCoreModule), typeof(AbpProjectNameTestModule) )] public class AbpProjectNameWebModule : AbpModule { private readonly IConfigurationRoot _appConfiguration; //構造函數注入 construc inject private AbpProjectNameApplicationModule _appModule; private AbpProjectNameTestModule _testModule; //Property inject //public AbpProjectNameApplicationModule _appModule { get; set; } public AbpProjectNameWebModule(IWebHostEnvironment env) { _appConfiguration = AppConfigurations.Get(env.ContentRootPath, env.EnvironmentName); //_appModule.A(); } public AbpProjectNameWebModule(AbpProjectNameApplicationModule appModule,AbpProjectNameTestModule testModule) { //構造函數注入 _appModule = appModule; _testModule = testModule; } public override void PreInitialize() { Configuration.DefaultNameOrConnectionString = _appConfiguration.GetConnectionString(AbpProjectNameConsts.ConnectionStringName); Configuration.Navigation.Providers.Add<AbpProjectNameNavigationProvider>(); Configuration.Modules.AbpAspNetCore() .CreateControllersForAppServices( typeof(AbpProjectNameApplicationModule).GetAssembly() ); //test1 _appModule.A(); //test2 //string str = _appModule.Bar(); //test3 //Baz baz = new Baz(); } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(AbpProjectNameWebModule).GetAssembly()); } public override void PostInitialize() { IocManager.Resolve<ApplicationPartManager>() .AddApplicationPartsIfNotAddedBefore(typeof(AbpProjectNameWebModule).Assembly); } }
View Code
其他東西先不要看,我們只看一句:
public AbpProjectNameWebModule(AbpProjectNameApplicationModule appModule,AbpProjectNameTestModule testModule) { //構造函數注入 _appModule = appModule; _testModule = testModule; }
在AbpProjectNameWebModule構造函數中,我們居然可以不用手動實例化AbpProjectNameApplicationModule和AbpProjectNameTestModule,就可以直接獲取到它們的實例了,是不是很神奇?當然是ABP框架在背後幫我們做了模組注入的事,具體可以看看AbpBootstrapper,AbpModuleManager,AbpModule等類的程式碼,重點關注模組管理類AbpModuleManager的RegisterModules方法,這個方法就是用來注入所有的模組,程式碼如下所示:
/// <summary> /// 將所有模組註冊到IOC容器 /// </summary> /// <param name="moduleTypes"></param> private void RegisterModules(ICollection<Type> moduleTypes) { foreach (var moduleType in moduleTypes) { _iocManager.RegisterIfNot(moduleType); } }
至於模組是怎麼載入的,怎樣註冊注入的,又是怎樣初始化和運行的,需要仔細分析上面幾個類的源程式碼,下篇再總結,上面涉及的程式碼也會以一個demo的形式發布出來。