一、前言

DI—Dependency Injection 依赖注入

IoC—Inversion of Control 控制反转

近几年这依赖注入、 控制反转已成为软件开发中不可或缺的一部分,那么该怎么理解这两个概念呢?

在阅读开始之前,大脑中先闪现几个问号???

.Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP

二、依赖注入

既然概念叫依赖注入,那首先分析一下什么是”依赖“?

依赖:是指一种特定的需求状态,在面向对象的软件开发过程中可以理解为对象A对另一对象B的一种引用关系。

下面以杀手刺杀举例说明依赖的关系:

.Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP.Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP

杀手需要一把枪来执行刺杀计划,这里从杀手的角度来看,对枪存在一种依赖关系,没有枪就不能成功刺杀。代码中表示如下:

public class Killer
{
    Gun gun = new Gun();
}

杀手只是需要一把枪,至于枪是如何生产的,杀手并不关心,我们改写下代码如下:

public class Killer
{
    private Gun _gun;
    public Killer(Gun gun)
    {
        _gun = gun;
    }
}

接着我们在Main方法中看下:

.Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP

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对象的”过程“,即把你所需要的赋给你的”过程“这就是依赖注入。

了解了什么是依赖注入?那它有什么好处呢?亦或者说依赖注入的目的是什么?

.Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP

在网上查找依赖注入概念时,控制反转往往与其同时出现。那么好,我们先来看看控制反转

三、控制反转

既然叫控制反转,那一定存在正向的了,那么什么算是正向的呢?

还是以杀手为例,

public Killer()
{
    Gun gun = new Gun();//创造一把枪
}

杀手自己创造一把枪,也就是自动去new即是正向

知道了正向,那么反向就不难理解了,杀手本身不去new,被动获取即是反向。那何来控制一说呢?

好我们继续看,先正向看,杀手创造一把枪(获取枪消耗时间,存在风险,可能错过最佳行刺时间)然后去刺杀,刺杀完成后还要销毁枪(销毁枪消耗时间,这个时间可能被抓,风险太大)。

public Killer()
{
    Gun gun = new Gun();//创造一把枪
    gun.Kill();//去行刺
    gun.Dispose();//销毁枪
 }

既然创造枪和销毁枪都有风险,和不将这两部分交给其他人去做?下面反向来了

杀手在整个刺杀行动中,首先会有专人给杀手枪(这个过程就是依赖注入),杀手完成刺杀行动后,会有专人进行枪的善后处理。

即把枪除了刺杀之外的整个枪的使用过程控制权完全交给第三方。

 .Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP

总结一下:这里的使用过程即可理解为对象(枪)的生命周期,第三方即是容器。容器接管了对象的创建、销毁的控制权。容器通过查找相关依赖动态的将对象(枪)注入给需求方(杀手)。

这种自身并不负责依赖对象的创建及销毁。由容器来管理控制的思想称之为控制反转

这里可以回答上面遗留的问题,依赖注入的目的是什么?目的是实现控制反转。

四、.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配置成功

.Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?-LMLPHP

五、结语

本文以杀手行刺为例简单说明了依赖注入、控制反转、IOC容器的概念及其联系。如有不正之处,请指正,感谢!

代码地址:https://gitee.com/sirius_machao/mweb-api

03-01 19:44