.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; }