基於DDD的.NET開發框架 - ABP依賴注入

返回ABP系列html

ABP是「ASP.NET Boilerplate Project (ASP.NET樣板項目)」的簡稱。git

ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程序的新起點,它旨在成爲一個通用的WEB應用程序框架和項目模板。github

ABP的官方網站:http://www.aspnetboilerplate.com數據庫

ABP官方文檔:http://www.aspnetboilerplate.com/Pages/Documents編程

Github上的開源項目:https://github.com/aspnetboilerplate設計模式

1、依賴注入概念

控制反轉(Inversion of Control,英文縮寫爲IoC)是一個重要的面向對象編程的法則來削減計算機程序的耦合問題,也是輕量級的Spring框架的核心。 控制反轉通常分爲兩種類型,依賴注入(Dependency Injection,簡稱DI)和依賴查找(Dependency Lookup)。依賴注入應用比較普遍。框架

依賴注入是一種軟件設計模式的一個或多個依賴項注入(或服務),或經過引用傳遞,爲依賴對象(或客戶)和客戶端狀態的一部分。模式之間創建一個客戶的依賴關係的行爲,它容許程序設計是鬆散耦合的,依賴倒置和單一職責原則。它直接對比service locator模式,它容許客戶瞭解他們所使用的系統找到依賴。ide

依賴注入不是目的,它是一系列工具和手段,最終的目的是幫助咱們開發出鬆散耦合、可維護、可測試的代碼和程序。這條原則的作法是你們熟知的面向接口,或者說是面向抽象編程。函數

理想的軟件開發設計是「高內聚,低耦合」,高內聚側重面向對象編程,低耦合側重面向接口編程,控制反轉、依賴注入、依賴倒置都蘊含着面向接口編程的思想。工具

控制反轉把傳統上由程序代碼直接操控的對象的調用權交給容器,經過容器來實現對象組件的裝配和管理。所謂的"控制反轉"概念就是對組件對象控制權的轉移,從程序代碼自己轉移到了外部容器。

依賴注入是經過反射(reflection)動態的向某個對象提供它所須要的其餘對象、

經常使用依賴注入框架:

Unity:微軟patterns&practicest團隊開發的IOC依賴注入框架,支持AOP橫切關注點。

MEF(Managed Extensibility Framework):是一個用來擴展.NET應用程序的框架,可開發插件系統。

Spring.NET:依賴注入、面向方面編程(AOP)、數據訪問抽象,、以及ASP.NET集成。

Autofac:最流行的依賴注入和IOC框架,輕量且高性能,對項目代碼幾乎無任何侵入性。

PostSharp:實現靜態AOP橫切關注點,使用簡單,功能強大,對目標攔截的方法無需任何改動。

Castle Windsor、StructureMap、Ninject

其實我感受Autofac挺好用的,一直用的Autofac,不知道到Castle Windsor怎麼樣。

2、三層和DDD分層依賴關係

一、三層分層依賴以下圖:

從引用關係咱們就能知道各層的依賴關係:BLL須要依賴DAL,由於BLL中用到了DAL層的實體。UI這一層須要依賴BLL,還須要依賴DAL,由於在UI中也用到了DAL層實體。

若是從換個數據庫,DAL須要修改,那DAL的依賴也須要修改。

二、DDD分層依賴關係圖

從上圖能夠知道,表現層和數據訪問層都依賴領域模型層,這樣的話,若是咱們新添加一個UI界面;更換一種數據源的存儲和獲取方式,只須要修改對應層的代碼便可,領域模型層保持了穩定。

減小new引入的依賴及緊耦合最好的方式是使用構造函數注入依賴這種設計模式:即若是咱們須要一個依賴的實例,經過構造函數注入。

解耦和最重要的原則就是依賴倒置原則:

高層模塊不該該依賴底層模塊,他們都應該依賴抽象。抽象不該該依賴於細節,細節應該依賴於抽象。

簡單理解就是組件應該依賴於接口而不是實現。

3、ABP依賴注入底層實現

ABP依賴注入是經過Castle Windsor依賴注入的框架實現。

一、經過實現IConventionalDependencyRegistrar的實例定義注入的約定,而後經過IocManager來讀取這個規則完成依賴注入

代碼在Abp項目文件的Dependency文件夾下

 1)在PreInitialize方法中給IocManager的IConventionalDependencyRegistrar的list中加入BasicConventionalRegistrar

IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar());

2)IocManager維護了一個叫_conventionalRegistrars的list,其中的元素類型就是IConventionalDependencyRegistrar。接着IocManager的RegisterAssemblyByConvention是在模塊的Initialize方法中被調用

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());            
        }

3)IocManager在RegisterAssemblyByConvention方法中遍歷這個list,並根據IConventionalDependencyRegistrar的實例中定義的規則來完成register。

        /// <summary>
        /// Registers types of given assembly by all conventional registrars. See <see cref="AddConventionalRegistrar"/> method.
        /// </summary>
        /// <param name="assembly">Assembly to register</param>
        public void RegisterAssemblyByConvention(Assembly assembly)
        {
            RegisterAssemblyByConvention(assembly, new ConventionalRegistrationConfig());
        }

        /// <summary>
        /// Registers types of given assembly by all conventional registrars. See <see cref="AddConventionalRegistrar"/> method.
        /// </summary>
        /// <param name="assembly">Assembly to register</param>
        /// <param name="config">Additional configuration</param>
        public void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config)
        {
            var context = new ConventionalRegistrationContext(assembly, this, config);

            foreach (var registerer in _conventionalRegistrars)
            {
                registerer.RegisterAssembly(context);
            }

            if (config.InstallInstallers)
            {
                IocContainer.Install(FromAssembly.Instance(assembly));
            }
        }

 

二、直接使用IocManager的Register方法直接完成注入

AbpModule有個受保護的IocManager的成員,因此AbpModule的派生類均可以使用這個IocManager完成註冊。

public class AbpWebModule : AbpModule
    {
        /// <inheritdoc/>
        public override void PreInitialize()
        {
            if (HttpContext.Current != null)
            {
                XmlLocalizationSource.RootDirectoryOfApplication = HttpContext.Current.Server.MapPath("~");
            }
            //IocManager直接注入
            IocManager.Register<IAbpWebModuleConfiguration, AbpWebModuleConfiguration>();

            Configuration.Localization.Sources.Add(
                new DictionaryBasedLocalizationSource(
                    AbpWebLocalizedMessages.SourceName,
                    new XmlEmbeddedFileLocalizationDictionaryProvider(
                        Assembly.GetExecutingAssembly(), "Abp.Web.Localization.AbpWebXmlSource"
                        )));
        }

        /// <inheritdoc/>
        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());            
        }
    }