.Net Core 3.1瀏覽器後端服務(四) 你眼中的依賴注入與我相同嗎?

鹹魚翻身?發表於2021-03-01

一、前言

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

 

相關文章