.net core 源码分析(7) 启动过程-InitializeServiceProvider

InitializeServiceProvider 它负责在应用启动时,基于 ServiceCollection 创建并配置应用程序的 IServiceProvider 实例。这个过程在应用启动的第四阶段执行。

 [MemberNotNull(nameof(_appServices))]
 private void InitializeServiceProvider()
 {
   //创建ServiceCollection
var services = new ServiceCollection(); PopulateServiceCollection( services, _hostBuilderContext!, _hostingEnvironment!, _defaultProvider!, _appConfiguration!, () => _appServices!);
   //在这里StartUp.ConfigureServices()方法被执行
foreach (Action<HostBuilderContext, IServiceCollection> configureServicesAction in _configureServicesActions) { configureServicesAction(_hostBuilderContext!, services); }    //创建containerBuilder ,可以通过使用自定义的ServiceProviderFactory来实现替换掉.net core 默认的依赖注入容器和IServiceProvider,后期会单独讲解 object containerBuilder = _serviceProviderFactory.CreateBuilder(services);
   //这里执行了Startup.ConfigureContainer方法
foreach (IConfigureContainerAdapter containerAction in _configureContainerActions) { containerAction.ConfigureContainer(_hostBuilderContext!, containerBuilder); } _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder); }

 该方法执行的第一步骤就是创建ServiceCollection对象。ServiceCollection对象用于保存依赖注入中接口和实现类的对应关系,每条对应关系都被记录在ServiceDescriptor对象中 。

 在使用依赖注入的情况下,常见的使用场景主要分一下几种。

1:注册一个接口IService的实现类ImplementationService,这也是最常见的场景。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
         // 添加依赖注入服务
        services.AddSingleton<IMyService, MyImplementationService>();
        services.AddScoped<IMyService, MyImplementationService>();
        services.AddTransient<IMyService, MyImplementationService>();
        // 其他服务注册
        services.AddControllersWithViews(); // 如果你在使用 MVC 模式
    }

}
        

2:当我们希望把一个已经完成创建对象注册到服务中 ,在需要他的地方直接返回该对象。 或者注册一个工厂方法 到服务中,来实现根据不同情况来注入不同实现类的功能。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 1. 注入现有实例
        var myServiceInstance = new MyService { Name = "My Custom Service" };
        services.AddSingleton<IMyService>(myServiceInstance);

        // 2. 使用工厂方法注入自定义对象
        services.AddSingleton<IMyService>(provider =>
        {
            // 在这里可以自定义 MyService 的创建过程
            return new MyService { Name = "My Service Created by Factory" };
        });

        // 其他服务注册
        services.AddControllersWithViews(); // 如果你在使用 MVC 模式
    }

}

 依赖注入不是本篇主要讲述的内容,后边会单独出一篇讲述.net core 依赖注入的源码讲解。下面我们来看一下在new ServiceCollection() 之后发生了什么。

[MemberNotNull(nameof(_appServices))]
internal static void PopulateServiceCollection(
    IServiceCollection services,
    HostBuilderContext hostBuilderContext,
    HostingEnvironment hostingEnvironment,
    PhysicalFileProvider defaultFileProvider,
    IConfiguration appConfiguration,
    Func<IServiceProvider> serviceProviderGetter)
{
    // 1. 注入 IHostingEnvironment 实例 
    #pragma warning disable CS0618 // Type or member is obsolete
    services.AddSingleton<IHostingEnvironment>(hostingEnvironment);
    #pragma warning restore CS0618

    // 2. 注入 IHostEnvironment 实例
    services.AddSingleton<IHostEnvironment>(hostingEnvironment);

    // 3. 将 HostBuilderContext 注册为单例
    services.AddSingleton(hostBuilderContext);

    // 4. 将配置对象注册为单例工厂方法,使其与服务提供者一起释放
    services.AddSingleton(_ => appConfiguration);

    // 5. 将已过时的 IApplicationLifetime 映射为 IHostApplicationLifetime
    #pragma warning disable CS0618
    services.AddSingleton(s => (IApplicationLifetime)s.GetRequiredService<IHostApplicationLifetime>());
    #pragma warning restore CS0618

    // 6. 注册 IHostApplicationLifetime 接口和其实现 ApplicationLifetime
    services.AddSingleton<IHostApplicationLifetime, ApplicationLifetime>();

    // 7. 添加应用程序生命周期管理服务
    AddLifetime(services);

    // 8. 注册 IHost 接口的实现,并在此过程中使用 serviceProviderGetter 来确保 IServiceProvider 被正确处置
    services.AddSingleton<IHost>(_ =>
    {
        // 使用 serviceProviderGetter 获取服务提供者
        IServiceProvider appServices = serviceProviderGetter();
        
        // 创建 Host 对象,并注册相关依赖
        return new Internal.Host(appServices,
            hostingEnvironment,
            defaultFileProvider,
            appServices.GetRequiredService<IHostApplicationLifetime>(),
            appServices.GetRequiredService<ILogger<Internal.Host>>(),
            appServices.GetRequiredService<IHostLifetime>(),
            appServices.GetRequiredService<IOptions<HostOptions>>());
    });

    // 9. 配置 HostOptions 的初始化设置
    services.AddOptions().Configure<HostOptions>(options => 
    { 
        options.Initialize(hostBuilderContext.Configuration); 
    });

    // 10. 添加日志记录服务
    services.AddLogging();

    // 11. 添加度量服务
    services.AddMetrics();
}

 这段代码的核心是通过依赖注入系统(IServiceCollection)配置 ASP.NET Core 应用程序的核心服务,确保在应用程序运行期间,各种服务被正确创建、管理和释放。注意到ServiceProviderGetter了么?在执行这个方法的时候IServceProvider还没有被创建。注意看这一点,通过Factoy的方式来把IHost注册到ServiceConllection中,但是IHost的这个Factory在执行的时候需要ServiceProvider.

 // 8. 注册 IHost 接口的实现,并在此过程中使用 serviceProviderGetter 来确保 IServiceProvider 被正确处置
    services.AddSingleton<IHost>(_ =>
    {
        // 使用 serviceProviderGetter 获取服务提供者
        IServiceProvider appServices = serviceProviderGetter();
        
        // 创建 Host 对象,并注册相关依赖
        return new Internal.Host(appServices,
            hostingEnvironment,
            defaultFileProvider,
            appServices.GetRequiredService<IHostApplicationLifetime>(),
            appServices.GetRequiredService<ILogger<Internal.Host>>(),
            appServices.GetRequiredService<IHostLifetime>(),
            appServices.GetRequiredService<IOptions<HostOptions>>());
    });

IHost只是通过这种方式被注册,但是此时还没有被创建,所以被注册的工厂还没执行,其实这个的工厂在创建ServiceProvider 之后才会被执行。在创建ServiceProvider的时候HostBuilder的私有属性 IServiceProvider _appServices就会被赋值,ServiceProviderGetter是一个指向私有属性 _appServices的委托。通过 执行serviceProviderGetter();就可以拿到被创建的ServiceProvider。

 [MemberNotNull(nameof(_appServices))]
 private void InitializeServiceProvider()
 {
   //创建ServiceCollection
     var services = new ServiceCollection();

     PopulateServiceCollection(
         services,
         _hostBuilderContext!,
         _hostingEnvironment!,
         _defaultProvider!,
         _appConfiguration!,
         () => _appServices!);

     foreach (Action<HostBuilderContext, IServiceCollection> configureServicesAction in _configureServicesActions)
     {
         configureServicesAction(_hostBuilderContext!, services);
     }

     object containerBuilder = _serviceProviderFactory.CreateBuilder(services);

     foreach (IConfigureContainerAdapter containerAction in _configureContainerActions)
     {
         containerAction.ConfigureContainer(_hostBuilderContext!, containerBuilder);
     }

     _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder);
 }

 此时ServiceProvider已经被创建完成了,私有属性 IServiceProvider已经被赋值了。下一步就该创建IHost了,那个ServiceProviderGetter的委托也该执行了。

/// <summary>
 /// Run the given actions to initialize the host. This can only be called once.
 /// </summary>
 /// <returns>An initialized <see cref="IHost"/></returns>
 /// <remarks>Adds basic services to the host such as application lifetime, host environment, and logging.</remarks>
 public IHost Build()
 {
     if (_hostBuilt)
     {
         throw new InvalidOperationException(SR.BuildCalled);
     }
     _hostBuilt = true;

     // REVIEW: If we want to raise more events outside of these calls then we will need to
     // stash this in a field.
     using DiagnosticListener diagnosticListener = LogHostBuilding(this);

     InitializeHostConfiguration();
     InitializeHostingEnvironment();
     InitializeHostBuilderContext();
     InitializeAppConfiguration();
     InitializeServiceProvider();
     //IHost已经被注册到ServiceConllection()中,单例的工厂方法,刚讲过,忘了就回去看一下。
     return ResolveHost(_appServices, diagnosticListener);
 }

创建IHost对象。其实就是第一次从依赖注入获取单例的对象,后边在需要的时候就不会再次执行被注册的工厂方法,都会访问同一个Host对象

internal static IHost ResolveHost(IServiceProvider serviceProvider, DiagnosticListener diagnosticListener)
{
    if (serviceProvider is null)
    {
        throw new InvalidOperationException(SR.NullIServiceProvider);
    }

   
    // resolve configuration explicitly once to mark it as resolved within the
    // service provider, ensuring it will be properly disposed with the provider
    _ = serviceProvider.GetService<IConfiguration>();
    //通过依赖注入获取单例的IHost对象,被注册的工厂方法被执行。
    var host = serviceProvider.GetRequiredService<IHost>();

    if (diagnosticListener.IsEnabled() && diagnosticListener.IsEnabled(HostBuiltEventName))
    {
        Write(diagnosticListener, HostBuiltEventName, host);
    }

    return host;
}

 

 

.net core 源码分析

posted @ 2024-08-21 15:29  Hi同学  阅读(23)  评论(0编辑  收藏  举报