dotNET Core 3.X 依赖注入
如果說在之前的 dotNET 版本中,依賴注入還是個比較新鮮的東西,那么在 dotNET Core 中已經(jīng)是隨處可見了,可以說整個 dotNET Core 的框架是構(gòu)建在依賴注入框架之上。本文說說對 dotNET Core 中依賴注入的理解。
什么是依賴
在面向?qū)ο蟮恼Z言中,所說的依賴通常指類與類之間的關(guān)系,比如有個用戶類 User 和日志類 Log , 在 User 類中需要記錄日志,就需要引入日志類 Log,這樣 User 類就對 Log 類產(chǎn)生了依賴,代碼如下:
public?class?User {private?Log?_log=new?Log();public?string?GetUserName(){_log.Write("獲取用戶名稱");return?"oec2003";} } public?class?Log {public?void?Write(string?message){Console.WriteLine(message);} }或者直接在類的方法中對其他類進(jìn)行了依賴,如下:
public?class?Dept {public?string?GetDeptNameByUserId(string?userId){return?"開發(fā)部";} } public?string?GetUserFullName(string?userId) {Dept?dept=new?Dept();return?$"oec2003({dept.GetDeptNameByUserId(userId)})"; }這樣的類與類之間的直接依賴有如下幾個問題:
要換一種 Log 的實現(xiàn)方式,所有引用的地方都要進(jìn)行修改;
如果整個項目中到處都是這種類與類之間的強(qiáng)關(guān)聯(lián),代碼維護(hù)會變得非常困難;
對單元測試不友好。
要解決上面的問題,需要將依賴的類抽象成接口,不直接依賴具體的實現(xiàn)類類,而是依賴接口,這就是面向?qū)ο蟮牧笤瓌t中的依賴倒置原則:高層模塊不應(yīng)該依賴于底層模塊,二者都應(yīng)該依賴于抽象;抽象不應(yīng)該依賴于實現(xiàn)細(xì)節(jié),實現(xiàn)細(xì)節(jié)應(yīng)該依賴于抽象。
User 類調(diào)整后的代碼如下:
public?interface?ILog {void?Write(string?message); } public?class?Log:ILog {public?void?Write(string?message){Console.WriteLine(message);} } public?class?User {private?ILog?_log;public?User(ILog?log){_log?=?log;}public?string?GetUserName(){_log.Write("獲取用戶名稱");return?"oec2003";} }創(chuàng)建了 ILog 接口;
User 類調(diào)整為對 ILog 的依賴;
在 User 中類添加構(gòu)造函數(shù),在構(gòu)造函數(shù)中傳入接口 ILog 的實例。
那么構(gòu)造函數(shù)中的實例什么時候創(chuàng)建呢?這時就需要用到注入了。
什么是注入?
在上面示例中,注入就是在某個時機(jī),將 ILog 的實例傳遞到 User 類的構(gòu)造函數(shù)中,而 User 類中根本就不關(guān)心 ILog 的實現(xiàn)。在 dotNET Core 中提供了一個內(nèi)置的服務(wù)容器 IServiceProvider,然后在 Startup 類的 ConfigureServices ?方法中進(jìn)行注冊,注冊代碼如下:
public?void?ConfigureServices(IServiceCollection?services) {services.AddSingleton<IUser,?User>();services.AddSingleton<ILog,?Log>();services.AddControllers(); }上面代碼中是以單例的模式進(jìn)行注冊;
將原來在 User 類中的對 Log 類的直接依賴,轉(zhuǎn)移到了 ConfigureServices 方法中,這便是控制反轉(zhuǎn)(IoC)了,Log 類采用什么實現(xiàn),不在 User 類中來控制,而是轉(zhuǎn)移到了框架層面。
借助框架的依賴注入,相比較我們自己在類中互相關(guān)聯(lián)依賴地去創(chuàng)建對象有以下好處:
方便管理類之間的依賴,對我們使用面向?qū)ο蟮脑O(shè)計原則有幫助;
代碼有更好的維護(hù)性和擴(kuò)展性;
可以方便管理各個對象的生命周期。
依賴注入核心類型
在 dotNET Core 中使用內(nèi)置的依賴注入需要引入 using Microsoft.Extensions.DependencyInjection;i 命名空間。相關(guān)的幾個核心類型如下:
IServiceCollection:利用此類的擴(kuò)展方法進(jìn)行服務(wù)的注冊;
IServiceProvider:由 IServiceCollection 創(chuàng)建的依賴注入容器體現(xiàn)為,IServiceProvider 接口;
ServiceDescriptor:具體注冊的服務(wù)的描述,IServiceProvider 就是通過這個描述來構(gòu)建我們需要的服務(wù)實例;
ServiceLifetime:一個服務(wù)生命周期的枚舉,有 Singleton、Scoped、Transient 三種類型。
服務(wù)注冊的生命周期
服務(wù)注冊的生命周期有三種:
Singleton:單例模式,創(chuàng)建在全局的 IServiceProvider 的根容器上;
Scoped:范圍模式,用 Scope 注冊的對象,在同一個 ServiceProvider 的 Scope 下相當(dāng)于單例;
Transient:瞬時模式,每次從容器獲取對象時都是得到的一個全新的對象。
下面用一個示例來看下這三種不同生命周期的區(qū)別
1、創(chuàng)建分別代表不同生命周期的接口和類,代碼如下:
public?interface?ISingletonService{} public?interface?IScopedService{} public?interface?ITransientService{}public?class?SingletonService:ISingletonService{} public?class?ScopedService:IScopedService{} public?class?TransientService:ITransientService{}?2、在 Controller 中創(chuàng)建接口方法:
[HttpGet] public?void?GetService([FromServices]ISingletonService?singleton1,[FromServices]ISingletonService?singleton2,[FromServices]IScopedService?scoped1,[FromServices]IScopedService?scoped2,[FromServices]ITransientService?transient1,[FromServices]ITransientService?transient2) {System.Console.WriteLine($"singleton1:{singleton1.GetHashCode()}");System.Console.WriteLine($"singleton2:{singleton2.GetHashCode()}");System.Console.WriteLine($"scoped1:{scoped1.GetHashCode()}");System.Console.WriteLine($"scoped2:{scoped2.GetHashCode()}");System.Console.WriteLine($"transient1:{transient1.GetHashCode()}");System.Console.WriteLine($"transient2:{transient2.GetHashCode()}"); }3、連續(xù)調(diào)用兩次該接口,輸入如下圖:
測試示例中每個不同生命周期的對象都通過 FromServices 的方式注入了兩次,分析結(jié)果如下:
Singleton:兩次請求的四個對象都相同;
Scoped:相同請求的兩個對象是一致,重新請求會生成新的對象;
Transient:兩次請求的四個對象都不相同,每次都構(gòu)建新的對象。
總結(jié)
依賴注入的目的是為了解耦;
不依賴于具體類,而是依賴抽象類或者接口,這叫依賴倒置;
把服務(wù)的注冊和實例化的工作交給 dotNET Core 框架,而不是在具體實現(xiàn)類中處理,這個叫控制反轉(zhuǎn)即IoC (Inversion of Control)
就先寫到這兒了,dotNET Core 框架本身的依賴注入功能已經(jīng)比較強(qiáng)大,但還是有些功能不能滿足,需要引入第三方的注入框架,關(guān)于如何引入第三方依賴注入框架以及為什么要用第三方依賴注入框架,后面單獨開篇寫。
示例代碼:https://github.com/oec2003/DotNetCoreThreeAPIDemo/tree/master/InjectDemo
總結(jié)
以上是生活随笔為你收集整理的dotNET Core 3.X 依赖注入的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全局变量初始化顺序探究
- 下一篇: 【壹刊】Azure AD(三)Azure