ABP是“ASP.NET Boilerplate Project (ASP.NET樣板項目)”的簡稱。
ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程序的新起點,它旨在成為一個通用的WEB應用程序框架和項目模板。
ABP的官方網站:http://www.aspnetboilerplate.com
ABP官方文檔:http://www.aspnetboilerplate.com/Pages/Documents
Github上的開源項目:https://github.com/aspnetboilerplate
一、依賴注入概念
控制反轉(Inversion of Control,英文縮寫為IoC)是一個重要的面向對象編程的法則來削減計算機程序的耦合問題,也是輕量級的Spring框架的核心。 控制反轉一般分為兩種類型,依賴注入(Dependency Injection,簡稱DI)和依賴查找(Dependency Lookup)。依賴注入應用比較廣泛。
依賴注入是一種軟件設計模式的一個或多個依賴項注入(或服務),或通過引用傳遞,為依賴對象(或客戶)和客戶端狀態的一部分。模式之間建立一個客戶的依賴關系的行為,它允許程序設計是松散耦合的,依賴倒置和單一職責原則。它直接對比service locator模式,它允許客戶了解他們所使用的系統找到依賴。
依賴注入不是目的,它是一系列工具和手段,最終的目的是幫助我們開發出松散耦合、可維護、可測試的代碼和程序。這條原則的做法是大家熟知的面向接口,或者說是面向抽象編程。
理想的軟件開發設計是“高內聚,低耦合”,高內聚側重面向對象編程,低耦合側重面向接口編程,控制反轉、依賴注入、依賴倒置都蘊含着面向接口編程的思想。
控制反轉把傳統上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現對象組件的裝配和管理。所謂的"控制反轉"概念就是對組件對象控制權的轉移,從程序代碼本身轉移到了外部容器。
依賴注入是通過反射(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怎么樣。
二、三層和DDD分層依賴關系
1、三層分層依賴如下圖:
從引用關系我們就能知道各層的依賴關系:BLL需要依賴DAL,因為BLL中用到了DAL層的實體。UI這一層需要依賴BLL,還需要依賴DAL,因為在UI中也用到了DAL層實體。
如果從換個數據庫,DAL需要修改,那DAL的依賴也需要修改。
2、DDD分層依賴關系圖
從上圖可以知道,表現層和數據訪問層都依賴領域模型層,這樣的話,如果我們新添加一個UI界面;更換一種數據源的存儲和獲取方式,只需要修改對應層的代碼即可,領域模型層保持了穩定。
減少new引入的依賴及緊耦合最好的方式是使用構造函數注入依賴這種設計模式:即如果我們需要一個依賴的實例,通過構造函數注入。
解耦和最重要的原則就是依賴倒置原則:
高層模塊不應該依賴底層模塊,他們都應該依賴抽象。抽象不應該依賴於細節,細節應該依賴於抽象。
簡單理解就是組件應該依賴於接口而不是實現。
三、ABP依賴注入底層實現
ABP依賴注入是通過Castle Windsor依賴注入的框架實現。
1、通過實現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)); } }
2、直接使用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()); } }