一、前言
DI—Dependency Injection 依賴注入
IoC—Inversion of Control 控制反轉
近幾年這依賴注入、 控制反轉已成為軟體開發中不可或缺的一部分,那麼該怎麼理解這兩個概念呢?
在閱讀開始之前,大腦中先閃現幾個問號???
二、依賴注入
既然概念叫依賴注入,那首先分析一下什麼是”依賴“?
依賴:是指一種特定的需求狀態,在物件導向的軟體開發過程中可以理解為物件A對另一物件B的一種引用關係。
下面以殺手刺殺舉例說明依賴的關係:
殺手需要一把槍來執行刺殺計劃,這裡從殺手的角度來看,對槍存在一種依賴關係,沒有槍就不能成功刺殺。程式碼中表示如下:
public class Killer { Gun gun = new Gun(); }
殺手只是需要一把槍,至於槍是如何生產的,殺手並不關心,我們改寫下程式碼如下:
public class Killer { private Gun _gun; public Killer(Gun gun) { _gun = gun; } }
接著我們在Main方法中看下:
Killer的構造方法中需要Gun,我需要你。。。,即是我(Killer)對你(Gun)有所依賴,這就是依賴。
那什麼是依賴注入呢?既然殺手需要一把槍,那麼Main方法就提供一個Gun物件並賦予給Killer,程式碼如下:
public class Program { static void Main(string[] args) { Gun gun = new Gun(); Killer killer = new Killer(gun); } }
在我看來Main方法賦予給殺手gun物件的”過程“,即把你所需要的賦給你的”過程“這就是依賴注入。
瞭解了什麼是依賴注入?那它有什麼好處呢?亦或者說依賴注入的目的是什麼?
在網上查詢依賴注入概念時,控制反轉往往與其同時出現。那麼好,我們先來看看控制反轉
三、控制反轉
既然叫控制反轉,那一定存在正向的了,那麼什麼算是正向的呢?
還是以殺手為例,
public Killer() { Gun gun = new Gun();//創造一把槍 }
殺手自己創造一把槍,也就是自動去new即是正向。
知道了正向,那麼反向就不難理解了,殺手本身不去new,被動獲取即是反向。那何來控制一說呢?
好我們繼續看,先正向看,殺手創造一把槍(獲取槍消耗時間,存在風險,可能錯過最佳行刺時間)然後去刺殺,刺殺完成後還要銷燬槍(銷燬槍消耗時間,這個時間可能被抓,風險太大)。
public Killer() { Gun gun = new Gun();//創造一把槍 gun.Kill();//去行刺 gun.Dispose();//銷燬槍
}
既然創造槍和銷燬槍都有風險,和不將這兩部分交給其他人去做?下面反向來了
殺手在整個刺殺行動中,首先會有專人給殺手槍(這個過程就是依賴注入),殺手完成刺殺行動後,會有專人進行槍的善後處理。
即把槍除了刺殺之外的整個槍的使用過程的控制權完全交給第三方。
總結一下:這裡的使用過程即可理解為物件(槍)的生命週期,第三方即是容器。容器接管了物件的建立、銷燬的控制權。容器通過查詢相關依賴動態的將物件(槍)注入給需求方(殺手)。
這種自身並不負責依賴物件的建立及銷燬。由容器來管理控制的思想稱之為控制反轉。
這裡可以回答上面遺留的問題,依賴注入的目的是什麼?目的是實現控制反轉。
四、.net core中使用依賴注入
瞭解了依賴注入和控制反轉後,來看看.net core中在哪裡進行的依賴注入,接下來回歸我們的專案
1、.net core自身的IOC容器
NET Core自身整合了一個輕量級的IOC容器,只要在Startup.cs的ConfigureServices方法中進行配置即可,如之前配置的使用者資訊服務
public void ConfigureServices(IServiceCollection services) { services.AddScoped<IUserInfoRepository, UserInfoRepository>(); services.AddScoped<IUserInfoServices, UserInfoServices>(); }
這裡需要注意一點,配置注入的生命週期。有三種注入的生命週期
AddSingleton 單一例項物件整個程式執行期間都是相同的(相當於單例模式,例如:全域性配置資訊,統計線上人數)
AddScoped 對每次請求而言物件是相同的,但在請求之間不同(例如:獲取使用者資訊,每個使用者均請求自身的物件)
AddTransient 每次請求物件都是不同的(暫未找到合適的應用場景,如有合適的請告知)
.Net Core自身的IOC容器比較簡單,如果想要更多的功能和擴充套件,還需要第三方的框架支援。
2、第三方IOC容器
.Net Core 有多種三方容器 如:Autofac、DryIoc、Grace、lightInject等等。評價較好的是Autofac,我們這裡也使用Autofac
在 Package Manager Console中輸入如下命令,安裝Autofac包
Install-Package Autofac -Version 6.1.0
Install-Package Autofac.Extensions.DependencyInjection -Version 7.1.0
替換預設的IOC容器,在Program類中的CreateHostBuilder方法中 將預設ServiceProviderFactory指定為AutofacServiceProviderFactory
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
在Startup類中新增如下方法:
public void ConfigureContainer(ContainerBuilder builder) { var basePath = AppContext.BaseDirectory; //Service所在程式集 string servicePath = Path.Combine(basePath, "MServices.dll"); Assembly serviceDll = Assembly.LoadFrom(servicePath); //Repository層所在程式集 string repositoryPath = Path.Combine(basePath, "MRepository.dll"); Assembly repositoryDll = Assembly.LoadFrom(repositoryPath); builder.RegisterAssemblyTypes(serviceDll) .AsImplementedInterfaces() .InstancePerDependency(); builder.RegisterAssemblyTypes(repositoryDll) .AsImplementedInterfaces() .InstancePerDependency(); }
移除之前ConfigureServices中的注入
services.AddScoped<IUserInfoRepository, UserInfoRepository>();
services.AddScoped<IUserInfoServices, UserInfoServices>();
執行專案,並呼叫介面,呼叫正常,說明Autofac配置成功
五、結語
本文以殺手行刺為例簡單說明了依賴注入、控制反轉、IOC容器的概念及其聯絡。如有不正之處,請指正,感謝!
程式碼地址:https://gitee.com/sirius_machao/mweb-api