1. 程式人生 > >【ABP框架系列學習】模組系統(4)

【ABP框架系列學習】模組系統(4)

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)。