Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kestrel 服务器源码解读和 IOC 容器依赖注入 DI #39

Open
Henrik-Xu opened this issue Mar 16, 2022 · 0 comments
Open

Kestrel 服务器源码解读和 IOC 容器依赖注入 DI #39

Henrik-Xu opened this issue Mar 16, 2022 · 0 comments

Comments

@Henrik-Xu
Copy link
Owner

Kestrel 服务器源码解读和 IOC 容器依赖注入 DI

源码分析

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

CreateDefaultBuilder 方法

  1. 启动必须的配置:比如监听的端口,url 地址等。

  2. 程序自定义配置,从 appsettings.jsonappsettings.[EnvironmentName].json、环境变量、命令行参数和其他配置源中加载。

  3. 日志系统的配置:将日志记录输送发送到控制台等。

ConfigureWebHostDefaults 方法

  1. 指定和配置 web 服务器:将 Kestrel 服务器用作 web 服务器并启用 IIS 集成。

为什么要用 HostBuilder?

  1. Host 的职责只是完成主机该有的功能。

  2. 因为 Host 创建过程非常复杂,所以它的创建及其配置由一个特定的 HostBuilder 类完成,它是 Host 的创建器(工厂)。

Asp.net Core 的启动步骤

Asp.net Core 的启动步骤

Asp.net Core 主机内部的执行流程

public static IHostBuilder CreateHostBuilder(string[] args)
{
    IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args);
  
    hostBuilder.ConfigureAppConfiguration(configure =>
    {
        Console.WriteLine("1. ConfigureAppConfiguration");
    });
    hostBuilder.ConfigureHostConfiguration(configure =>
    {
        Console.WriteLine("2. ConfigureHostConfiguration");
    });
    hostBuilder.ConfigureServices(configure =>
    {
        Console.WriteLine("3. ConfigureServices");
    });
    hostBuilder.ConfigureWebHostDefaults(webBuilder =>
    {
        Console.WriteLine("4. ConfigureWebHostDefaults");
        webBuilder.UseStartup<Startup>();
    });


    return hostBuilder;
}

// output : 4,2,1,3

Asp.net Core 主机内部的执行流程

.NetCore 内置容器

.NetCore 里面默认提供一个服务注册和获取的容器,为什么要用这个容器呢?

我们写完了各种对象,在使用的时候,肯定去 new,这个是经常的操作。

试想另一种情况:如果我们在一个系统中,用的对象非常多,你就得不断的去new对象。

问题:处处在new是不是很麻烦?扩展也是不现实的。

想法:能不能别人帮我new?我想用什么,就得到什么?我们是用对象容器,就是帮我们生成这些对象,

并且对对象的生命周期,统一管理。

好处:不仅能够精确的控制对象的生命周期,而且,还能自动的创建依赖对象

看一下的问题,接口类:

public interface IServiceA
{
    void Operation();
}

public interface IServiceB
{
    void Operation();
}

public interface IServiceC
{
    void Operation();
}

public interface IServiceD
{
    void Operation();
}

接口的实现:

/// <summary>
/// 服务A的实现
/// </summary>
public class ObjectA : IServiceA
{
  public ObjectA()
  {
      Console.WriteLine("ObjectA  is Created!");
  }
  public void Operation()=> Console.WriteLine("ObjectA.Operation()  is Called!");        
}

/// <summary>
/// 服务B的实现
/// </summary>
public class ObjectB : IServiceB
{
  private readonly IServiceA serviceA;
  public ObjectB(IServiceA service)
  {
      this.serviceA = service;
      Console.WriteLine("ObjectB  is Created!");           
  }
  public void Operation()
  {
      Console.WriteLine("--------------------------------------------");
      this.serviceA.Operation();
      Console.WriteLine("ObjectB.Operation()  is Called!");
  }
}

/// <summary>
/// 服务C的实现
/// </summary>
public class ObjectC : IServiceC
{       
  private readonly IServiceB serviceB;
  public ObjectC(IServiceB service)
  {
      this.serviceB = service;
      Console.WriteLine("ObjectC  is Created!");          
  }
  public void Operation() => Console.WriteLine("ObjectC.Operation()  is Called!");       
} 

/// <summary>
/// 服务D的实现
/// </summary>
public class ObjectD : IServiceD
{
  private readonly IServiceA _serviceA; 
  private readonly IServiceB _serviceB;
  private readonly IServiceC _serviceC;
  public ObjectD(IServiceA serviceA, IServiceB serviceB, IServiceC serviceC)
  {
      this._serviceA = serviceA;
      this._serviceB = serviceB;
      this._serviceC = serviceC;
      Console.WriteLine("ObjectD  is Created!");            
  }
  public void Operation()
  {
      Console.WriteLine("---------------------------------------");
      this._serviceA.Operation();
      this._serviceB.Operation();
      this._serviceC.Operation();
      Console.WriteLine("ObjectD.Operation()  is Called!");
  }
}

main 方法里

static void Main(string[] args)
{
    ObjectA obj = new ObjectA(); //直接new 对象

    IServiceA a = new ObjectA(); // 基于接口,半解耦
    IServiceB b = new ObjectB(a);
    IServiceC c = new ObjectC(b);
    IServiceD d = new ObjectD(a,b,c)
}

问题:

  1. 以前方法对于对象之间的关联创建,非常麻烦。因为一个对象所关联的其他对象,必须全部提前创建。

  2. 这种需求,即使我们以前所学的工厂模式,也很难做到。

Nuget 引入 DI

using Microsoft.Extensions.DependencyInjection;

static void Main(string[] args)
{
    //【1】创建服务容器
    IServiceCollection services = new ServiceCollection();

    //【2】注册服务
    services.AddTransient<IServiceA, ObjectA>();
    services.AddSingleton<IServiceB, ObjectB>();
    services.AddScoped<IServiceC, ObjectC>();
    services.AddTransient<IServiceD, ObjectD>();

    //【3】创建服务提供者对象
    IServiceProvider serviceProvider = services.BuildServiceProvider();

    //【4】获取服务 - 可能在系统的其他地方
    //IServiceA instanceA = serviceProvider.GetService<IServiceA>();

    IServiceD instanceD = serviceProvider.GetService<IServiceD>();
    // instanceA.Operation();
    Console.Read();
}

引入 Ioc 概念

  1. Ioc(Inverse of Control) 控制反转: 就是将对象的控制权由我们开发者转移到容器。

  2. 好处:开发者不用关注细节,只需要关注抽象接口,非常有利于组件化开发。

依赖注入 DIIoc 容器

基于 Ioc 容器的 DI 框架两大核心

  1. 服务注册

  2. 服务提供

DI : Dependency Injection 思想

  1. 服务的使用者基于一个容器(Container)来得到需要的对象,容器在这个对象过程中自动完成所有依赖对象的创建。

常见 DI 容器

  1. Autofac

  2. Unity

  3. Spring.Net

IocDI 的区别

  1. Ioc :调用者不关心对象的创建,由 Ioc 容器完成,体现的是一种控制权的转移。

  2. DI: 基于 Ioc 容器创建需要的对象,同时能够自动完成所依赖对象的创建。体现的是一种依赖对象自动的注入。

总结

ASPNETCore 程序启动的核心方法源码分析

  1. CreateDefaultBuilder() 方法

  2. ConfigureWebHostDefault() 方法

  3. 细化 ASP.NET Core 主机内部的执行流程

Ioc 容器的使用

  1. IServiceCollection

  2. 服务注册的三种生命周期 Transient Singleton Scoped

  3. IServiceProvider

  4. GetService() 方法

依赖注入 DI

  1. 思想:体现的是对象创建中所依赖的对象的自动创建。

  2. 好处:让模块化开发更加富有弹性。

@Henrik-Xu Henrik-Xu changed the title 39 Kestrel 服务器源码解读和 IOC 容器依赖注入 DI Mar 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant