日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ABP理论学习之依赖注入

發布時間:2024/4/17 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ABP理论学习之依赖注入 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

返回總目錄


本篇目錄

  • 什么是依賴注入
    • 傳統方式產生的問題
    • 解決辦法
    • 依賴注入框架
  • ABP中的依賴注入基礎設施
    • 注冊
    • 解析
    • 其他
    • ASP.NET MVC和ASP.NET Web API集成
    • 最后提示

什么是依賴注入

維基百科說:“依賴注入是一種軟件設計模式,在這種模式下,一個或更多的依賴(或服務)被注入(或者通過引用傳遞)到一個獨立的對象(或客戶端)中,然后成為了該客戶端狀態的一部分。該模式分離了客戶端依賴本身行為的創建,這使得程序設計變得松耦合,并遵循了依賴反轉和單一職責原則。與服務定位器模式形成直接對比的是,它允許客戶端了解客戶端如何使用該系統找到依賴”。

不使用依賴注入技巧來管理依賴,并開發一個模塊化的,結構友好的應用是非常困難的。

傳統方式產生的問題

在一個應用中,類相互依賴。假設我們有個應用服務,該應用服務使用了倉儲將實體插入數據庫。在這種情況下,此應用服務類依賴于倉儲類。看下面這個例子:

public class PersonAppService {private IPersonRepository _personRepository;public PersonAppService(){_personRepository = new PersonRepository(); }public void CreatePerson(string name, int age){var person = new Person { Name = name, Age = age };_personRepository.Insert(person);} }

PersonAppService使用了PersonRepository將一個 Person插入到數據庫中。此處代碼的問題在于:

  • PersonAppService在CreatePerson方法中使用了IPersonRepository的引用,因此該方法依賴于IPersonRepository,而不是具體的PersonRepository類。但是在PersonAppService的構造函數中仍舊依賴于PersonRepository。而組件應該依賴于接口而不是實現,這就是依賴反轉原則。
  • 如果PersonAppService創建了PersonRepository本身,那么它會依賴于IPersonRepository接口的一個具體實現,這樣就造成可能不會和其他實現一起工作。因此,從實現中分離接口就會變得毫無意義。硬依賴使得代碼基變得緊耦合,可復用性降低。
  • 在未來我們可能需要改變PersonRepository的創建。比如,我們可能想要它是單例的(單一公用的實例而不是每次使用都創建一個對象)?;蛘呶覀兛赡懿恢箷摻▽崿F了IPersonRepository的一個類,也可能想要有條件地創建這些實現類中的一個。這種情況下,我們就要改變依賴IPersonRepository的所有類,這樣太不方便了,或者說維護難度太大了。
  • 測試方面,有了這么個依賴,對于PersonAppService的單元測試非常難(或者根本不可能)。

為了克服這些問題,可以使用工廠模式。因此,倉儲類的創建時抽象的。看下面的代碼:

public class PersonAppService {private IPersonRepository _personRepository;public PersonAppService(){_personRepository = PersonRepositoryFactory.Create(); }public void CreatePerson(string name, int age){var person = new Person { Name = name, Age = age };_personRepository.Insert(person);} }

PersonRepositoryFactory是一個創建并返回一個IPersonRepository的靜態類。這就是所謂的服務定位器模式。這樣創建問題是解決了,因為PersonAppService不知道如何創建一個IPersonRepository的實現,而且它獨立于PersonRepository的實現。但是,仍然有下面這些問題:

  • 這次,PersonAppService依賴于PersonRepositoryFactory。這個較為可接受,但是仍然有硬依賴。
  • 為每個倉儲或者依賴寫一個工廠類或方法太繁瑣了。
  • 還是不太好測試,因為讓PersonAppService使用一些IPersonRepository的偽造實現還是很困難。

解決辦法

要依賴其他的類有一些最佳實踐(模式)。

構造函數注入模式

上面的例子可以重寫為下面的代碼:

public class PersonAppService {private IPersonRepository _personRepository;public PersonAppService(IPersonRepository personRepository){_personRepository = personRepository;}public void CreatePerson(string name, int age){var person = new Person { Name = name, Age = age };_personRepository.Insert(person);} }

這就是所謂的構造函數注入?,F在,PersonAppService不知道哪一個類實現了IPersonRepository,也不知道如何創建的它。誰要使用PersonAppService,首先要創建一個IPersonRepository,并將它傳給PersonAppService的構造函數,如下所示:

var repository = new PersonRepository(); var personService = new PersonAppService(repository); personService.CreatePerson("Yunus Emre", 19);

構造函數注入是使類獨立于依賴對象創建的一種完美方式,但是,上面的代碼存在一些問題:

  • 創建一個PersonAppService變得更加困難。試想如果它有4個依賴,那么我們必須創建這4個依賴的對象,然后把它們傳入PersonAppService的構造函數中。
  • 依賴的類可能有其它的依賴(這里,PersonRepository可能有依賴)。因此,我們必須創建PersonAppService的所有依賴,依賴的所有依賴等等。這樣的話,我們甚至可能不再創建單一對象,因為依賴圖太復雜了。

幸運的是,ABP有依賴注入框架自動管理依賴。

屬性注入模式

構造函數注入是提供一個類的依賴的完美模式。用這種方式,你可以不需要提供依賴就能創建一個類的實例,它也是顯示聲明該類需要滿足什么要求才能正確工作的強大方式。

但在某些情況下,該類依賴于其他的類而且其他的類沒有它也能工作。這對于關注度分離(比如日志記錄)來說經常是成立的。一個類可以離開logging工作,但如果提供了logger,那它就能記錄日志。這種情況下,你可以定義將依賴定義為公共的屬性而不是在構造函數中獲得這些依賴。試想如果我們要在PersonAppService中記錄日志,那么我們可以重寫該類為:

public class PersonAppService {public ILogger Logger { get; set; }private IPersonRepository _personRepository;public PersonAppService(IPersonRepository personRepository){_personRepository = personRepository;Logger = NullLogger.Instance;}public void CreatePerson(string name, int age){Logger.Debug("Inserting a new person to database with name = " + name);var person = new Person { Name = name, Age = age };_personRepository.Insert(person);Logger.Debug("Successfully inserted!");} }

NullLogger.Instance是一個實現了ILogger的單例對象,但實際上什么都沒做(沒有記錄日志,它使用了空的方法體實現了ILogger)。因此,如果你在創建PersonAppService對象之后,并像下面那樣設置了Logger,PersonAppService就可以記錄日志了:

var personService = new PersonAppService(new PersonRepository()); personService.Logger = new Log4NetLogger(); personService.CreatePerson("Yunus Emre", 19);

假設Log4NetLogger實現了ILogger并使用Log4Net類庫記錄日志。這樣,PersonAppService實際上就可以記錄日志了。如果沒有設置Logger,那么它就不會記錄日志。因此,我們可以說ILogger是PersonAppService的一個可選依賴。

幾乎所有的依賴注入框架都支持屬性注入模式。

依賴注入框架

有很多自動解析依賴的依賴注入框架。它們能夠使用所有的依賴(包括依賴的依賴)創建對象。因此,你只需要使用構造和屬性注入模式編寫你的類,DI框架會處理剩下的事情。在一個優秀的應用中,你的類甚至獨立于DI框架。在整個應用中,有許多顯式和DI框架交互的代碼行或者類。

ABP使用Castle Windsor框架處理依賴注入。它是最成熟的DI框架之一。還有很多其他的框架,如Unity,Ninject,StructureMap,Autofac等等。

在依賴注入框架中,你首先要將你的接口或者類注冊到其中,然后才可以解析(創建)一個對象。在Castle Windsor中,有點像下面那樣:

var container = new WindsorContainer();container.Register(Component.For<IPersonRepository>().ImplementedBy<PersonRepository>().LifestyleTransient(),Component.For<IPersonAppService>().ImplementedBy<PersonAppService>().LifestyleTransient());var personService = container.Resolve<IPersonAppService>(); personService.CreatePerson("Yunus Emre", 19);

上面的代碼中,首先創建了WindsorContainer,然后使用PersonRepository和PersonAppService的接口注冊了它們,再然后我們要求容器創建一個IPersonAppService。容器使用依賴創建了PersonAppService并返回,也許在這個簡單的例子中使用DI框架的優勢不是很明顯,但是想象一下你在一個真實的企業應用中會有很多類和依賴。當然,也會在別的地方使用對象來注冊依賴,這個在應用啟動時只會做一次。

注意,我們也將對象的生命周期聲明為transient。這意味著,無論何時解析這些類型的一個對象,都會創建一個新的實例。當然還有很多不同的生命周期(像singleton)。

ABP中的依賴注入基礎設施

當你通過下面的最佳實踐和一些慣例編寫你的應用時,ABP幾乎讓使用DI框架變得不可見了。

注冊

在ABP中,將你的類注冊到DI系統有幾種不同的方式。大多數情況下,按照慣例注冊已經足夠了。

慣例注冊

ABP會按照慣例自動注冊所有的倉儲,領域服務,應用服務,MVC控制器和Web API控制器。比如,你可能有一個IPersonAppService接口和一個實現了該接口的PersonAppService類:

public interface IPersonAppService : IApplicationService {//... }public class PersonAppService : IPersonAppService {//... }

因為它實現了IApplicationService接口(只是一個空接口),所以ABP會自動注冊它,并注冊為transient(每次使用創建一個實例)。當你使用構造函數注入IPersonAppService接口到一個類中時,一個PersonAppService對象會自動地創建并傳入該類的構造函數中。

命名規范在ABP中非常重要。比如,你可以將PersonAppService更名為MyPersonAppService或是其他包含了“PersonAppService”后綴的名字,因為IPersonAppService接口有這個后綴。但你不能將它命名為PeopleService。如果你沒有按照這種命名規范來操作的話,那么IPersonAppService不會自動地注冊(但是它已經以自注冊的方式注入到DI框架,而不是接口方式),因此如果你想要以接口方式注冊的話,那么你應該手動注冊。

ABP按照慣例注冊程序集。因此,你應該按照慣例告訴ABP注冊你的程序集。這個相當簡單:

IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());

Assembly.GetExecutingAssembly()會獲得包含這句代碼的程序集的引用。你也可以將其他的程序集傳入RegisterAssemblyByConvention 方法中。這個操作通常在你的模塊初始化的時候完成的。查看《模塊系統》博文獲得更多信息。

通過實現IConventionalRegister接口和調用IocManager.AddConventionalRegister方法,你可以用你的類編寫你自己的慣例注冊類。你要做的就是在模塊的PreInitialize方法中加入它。

幫助接口

你可能想要注冊一個特殊的類,但是它不符合慣例注冊的原則。為此,ABP提供了ITransientDependencyISingletonDependency接口。比如:

public interface IPersonManager {//... }public class MyPersonManager : IPersonManager, ISingletonDependency {//... }

用這種方式,你可以輕松地注冊MyPersonManager。當需要注入IPersonManager的時候,就會使用MyPersonManager。注意依賴聲明為Singleton。這樣,MyPersonManager的單例就被創建了,并且相同的對象也被傳入到所有的類中。只有在第一次使用時才會創建,以后再整個應用的生命周期都會使用相同的實例。

自定義/直接注冊

如果之前描述的方法還不能滿足你,那么你可以直接使用Castle Windsor來注冊你的類和依賴。這樣,你就在Castle Windsor中注冊任何東西。

Castle Windsor有一個為了注冊而要實現的接口IWindsorInstaller。你可以在應用中創建實現了IWindsorInstaller接口的類:

public class MyInstaller : IWindsorInstaller {public void Install(IWindsorContainer container, IConfigurationStore store){container.Register(Classes.FromThisAssembly().BasedOn<IMySpecialInterface>().LifestylePerThread().WithServiceSelf());} }

ABP會自動找到并執行這個類。最后,可以使用IIocManager.IocContainer屬性到達WindsorContainer。獲取更多Windsor信息,請查看官方文檔。

解析

注冊會將你的類,類的依賴和生命周期通知給IOC(控制反轉)容器。接下來,你需要在應用中的某些地方使用IOC容器創建對象。ABP針對依賴的解析提供了很多選項。

構造函數&屬性注入

你可以將使用構造函數和屬性注入獲得類的依賴作為最佳實踐。無論在哪里,你都應該這樣做。例如:

public class PersonAppService {public ILogger Logger { get; set; }private IPersonRepository _personRepository;public PersonAppService(IPersonRepository personRepository){_personRepository = personRepository;Logger = NullLogger.Instance;}public void CreatePerson(string name, int age){Logger.Debug("Inserting a new person to database with name = " + name);var person = new Person { Name = name, Age = age };_personRepository.Insert(person);Logger.Debug("Successfully inserted!");} }

IPersonRepository從構造函數注入,ILogger使用公共屬性注入。這樣的話,你的代碼根本意識不到依賴注入系統的存在,也就是說,依賴系統對于我們開發者完全是透明的,我們可以不考慮依賴系統內部的實現細節。這是使用DI系統最合適的方式。

IIocResolver和IIocManager

有時,你可能必須要直接解析依賴而不是通過構造函數和屬性注入。這種情況要盡可能地避免,但這種情況也是有可能的。ABP提供了很多可以輕松注入并使用的服務。例如:

public class MySampleClass : ITransientDependency {private readonly IIocResolver _iocResolver;public MySampleClass(IIocResolver iocResolver){_iocResolver = iocResolver;}public void DoIt(){//手動解析var personService1 = _iocResolver.Resolve<PersonAppService>();personService1.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });_iocResolver.Release(personService1);//安全地解析并使用using (var personService2 = _iocResolver.ResolveAsDisposable<PersonAppService>()){personService2.Object.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });}} }

在以上例子中的MySampleClass通過構造函數注入IIocResolver并用它來解析和釋放對象。Resolve方法有許多重載可供使用。Release方法用來釋放組件(對象)。調用Release來手動解析一個對象是很關鍵的,否則,應用會有內存泄漏問題。為了確保釋放對象,要盡可能使用ResolveAsDisPosable(如例子中演示的那樣)。在using塊的末尾會自動地調用Release。

如果你想要直接使用IOC容器(Castle Windor)來解析依賴,那么你可以構造函數注入IIocManager并使用IIocManager.IocContainer屬性。如果你處于靜態上下文或者不能注入IIocManager,那么最后的機會就是,你可以使用單例對象IocManager.Instance。但是,這種情況不容易測試。

其他

IShouldInitialize接口

某些類在第一次使用前就要初始化。IShouldInitialize接口有一個Initialize方法。如果實現了該接口,那么在創建對象之后(使用前)就會自動地調用Initialize方法。當然,為了使該功能有效,你應該注入/解析該對象。

ASP.NET MVC和ASP.NET Web API集成

當然,為了解析依賴圖中的根對象,我們必須調用依賴注入系統。在ASP.NET MVC應用中,根對象一般是一個Controller類。我們也可以在控制器中使用構造函數注入和屬性注入模式。當一個請求到達應用時,IOC容器創建了控制器對象,然后所有的依賴遞歸地解析出來。那么,誰處理的這個呢?這是ABP通過擴展了ASP.NET MVC默認的控制器工廠自動完成的。相似地,對于ASP.Net Web API也是如此。你不必關心創建和釋放對象的事情。

最后提示

只要你遵循規則并使用上面的結構,ABP就能簡化并自動化依賴注入的使用。大多數情況下,這些已經夠用了。但是,如果你需要的話,你可以直接使用所有Castle Windsor的能力來執行任何任務(如自定義注冊,注入鉤子,攔截器等等)。

轉載于:https://www.cnblogs.com/farb/p/ABPDependencyInjection.html

總結

以上是生活随笔為你收集整理的ABP理论学习之依赖注入的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 黄视频免费在线观看 | 中文字幕色图 | 黄色激情在线观看 | 亚洲色图在线视频 | 欧洲亚洲视频 | 亚洲m码 欧洲s码sss222 | 国产一区二区视频在线免费观看 | 国产精品mv| 麻豆成人网 | 日韩专区一区二区三区 | 欧美黑人性受xxxx精品 | 91在线视频网址 | 免费日批视频 | 色欧洲| 久久一二区 | 韩国女主播一区 | 久久久久五月天 | 狠狠操在线播放 | 一卡二卡精品 | 欧美黄色大片网站 | 天天插天天摸 | 日韩一区二区三区不卡 | 在线观看午夜视频 | 日韩av在线不卡 | 久久成人在线视频 | 欧美com| 日韩高清一区 | 狠狠躁日日躁夜夜躁av | 涩涩屋视频在线观看 | 青草精品在线 | 久久久久亚洲av片无码v | 国产精品久久久久久久久免费相片 | 国产精品96久久久久久 | 欧美日韩在线一区 | 永久免费未满蜜桃 | 精品国产aⅴ一区二区三区四川人 | 天海翼av在线| 狠狠操狠狠爱 | 午夜久久| 亚洲国产精品成人综合 | 熟妇高潮一区二区高潮 | 熟妇人妻精品一区二区三区视频 | 中文在线观看av | 一本久久道 | 国产精品熟妇一区二区三区四区 | 日本特黄一级片 | 黑人操亚洲人 | 国产精品成av人在线视午夜片 | 午夜91| 中文字幕精品无码一区二区 | 91av视频免费观看 | 久久99国产综合精品免费 | 超碰成人在线免费观看 | 国产91av视频| 18禁一区二区 | 美女高潮在线 | 美女吞精视频 | 欧美日韩一级大片 | 最近日本中文字幕 | 91精品网站 | 永久免费网站直接看 | 亚洲国产97| 国产白浆在线 | 免费 成 人 黄 色 | 樱桃视频污污 | 无遮挡在线观看 | 婷婷六月天在线 | 手机看片福利视频 | 奇米四色在线视频 | 国产精品免费一区二区三区在线观看 | 国产中文字幕免费 | 国产精品高潮呻吟久久av野狼 | 一级做a爱片性色毛片 | 国产综合社区 | 国产一级片中文字幕 | 超碰97在线资源 | 夜夜天天操 | 国产一级黄色 | www.久久久久.com | 欧美在线视频网站 | 欧美一级片在线免费观看 | 中文字幕欧美视频 | 国产精彩视频一区二区 | 久久综合综合 | 成人片网址 | 成人国产精品免费观看视频 | 99黄色网| 不卡精品视频 | 亚洲婷婷在线视频 | 91成人一区二区三区 | 女性裸体无遮挡胸 | 亚洲在线日韩 | 成人永久免费视频 | 久久国产精品精品国产色婷婷 | 色老头在线观看 | 天天色综合天天 | 国产精品久久久久毛片软件 | 香港三级日本三级三69 | 日韩av在线天堂 |