考虑到主题问题, 在这里不打算详细讲解依赖注入的概念, 需要了解依赖注入的可以关注我的 DI&IoC 分类讲解, 这里我们专注于 ASP.NET Core 体系中系统自带的原生 IoC 容器是如何让我们实现注入和解析的.
服务的生命周期
在开始之前, 我们先了解一下服务的生命周期, 这仅涉及到 IServiceCollection 和 IServiceProvider 两个核心对象, 这也是我们开篇文章中阐述的两个重要对象.
在. NET Core 中 DI 的核心分为两个组件: IServiceCollection 和 IServiceProvider.
IServiceCollection 负责注册
IServiceProvider 负责提供实例
ActivatorUtilities(暂不讲解) 负责提供实例, 允许在依赖关系注入容器中创建没有服务注册的对象.
服务注册:
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddTransient<ITransientTest, TransientTest>();
- services.AddSingleton<ISingletonTest, SingletonTest>();
- services.AddScoped<IScopedTest, ScopedTest>();
- .....
- }
通过 IServiceCollection 这个对象, 系统将相应的服务以不同的生命周期模式 (Transient,Scoped 和 Singleton) 注册到 ServiceCollection 对象里面.
在此需要解释一下服务的生命周期
Singleton: 整个应用程序生命周期内只创建一个实例
Transient: 每一次请求都会创建一个新的实例
Scoped: 每次从同一个容器中获取的实例是相同的,
- interface ITransientTest { }
- interface ISingletonTest { }
- interface IScopedTest { }
- class TransientTest : ITransientTest { }
- class SingletonTest : ISingletonTest { }
- class ScopedTest : IScopedTest { }
- class Program
- {
- static void Main(string[] args)
- {
- IServiceCollection services = new ServiceCollection();
- services = services.AddTransient<ITransientTest, TransientTest>();
- services = services.AddScoped<IScopedTest, ScopedTest>();
- services = services.AddSingleton<ISingletonTest, SingletonTest>();
- IServiceProvider serviceProvider = services.BuildServiceProvider();
- Console.WriteLine(ReferenceEquals(serviceProvider.GetService<ITransientTest>(), serviceProvider.GetService<ITransientTest>()));
- Console.WriteLine(ReferenceEquals(serviceProvider.GetService<IScopedTest>(), serviceProvider.GetService<IScopedTest>()));
- Console.WriteLine(ReferenceEquals(serviceProvider.GetService<ISingletonTest>(), serviceProvider.GetService<ISingletonTest>()));
- IServiceProvider serviceProvider1 = serviceProvider.CreateScope().ServiceProvider;
- IServiceProvider serviceProvider2 = serviceProvider.CreateScope().ServiceProvider;
- Console.WriteLine(ReferenceEquals(serviceProvider1.GetService<IScopedTest>(), serviceProvider1.GetService<IScopedTest>()));
- Console.WriteLine(ReferenceEquals(serviceProvider1.GetService<IScopedTest>(), serviceProvider2.GetService<IScopedTest>()));
- Console.WriteLine(ReferenceEquals(serviceProvider1.GetService<ISingletonTest>(), serviceProvider2.GetService<ISingletonTest>()));
- /* False
- * True
- * True
- * True
- * False
- * True
- */
- }
- }
对象解析:
当我们需要从容器中解析一个对象出来的时候, 用到了 IServiceProvider 对象, 它根据 IServiceCollection 注册的服务类型提取相应的服务对象.
- public class Test
- {
- private readonly IServiceProvider _serviceProvider;
- public Test(IServiceProvider serviceProvider)
- {
- _serviceProvider = serviceProvider;
- }
- public TestController()
- {
- // 如果没有, 则返回 null
- var testService1 = _serviceProvider.GetService<ITestService>();
- // 如果没有, 则抛出 InvalidOperationException 异常
- var testService2 = _serviceProvider.GetRequiredService<ITestService>();
- // 获取对应的集合
- var testService3 = _serviceProvider.GetServices<ITestService>();
- var testService4 = _serviceProvider.GetRequiredServices<ITestService>();
- }
- }
整体的一个依赖注入流程如下图
追本溯源
在上面我们知道了如何通过 IServiceCollection 和 IServiceProvider 这两个对象注册和解析对象, 那么问题来了, 这两个对象是什么时候和如何创建的呢?
回到我们 ASP.NET Core - 从 Program 和 Startup 开始的控制台程序, 在 webHostBuilder 调用 Build 方法创建 WebHost 的过程中, 这时会创建一个 ServiceCollection 对象, 并将系统需要的一系列预定义服务 (如 IHostingEnvironment,IConfiguration,IHttpContextFactory,IStartupFilter 等) 注册在它之上. 接下来会利用这个 ServiceCollection 对象创建出对应的 ServieProvider(BuildServiceProvider()), 而这两个 ServiceProvider 和 ServiceCollection 对象会一并传递给最终创建的 WebHost,WebHost 会利用这个 ServiceProvider 对象解析出 Startup 对象, 并调用它的 Configure 方法用来完成对整个管道的建立.
非常值得一提的是, Startup 中的 ConfigureServices 方法是允许具有一个 IServiceProvider 类型的返回值, 如果这个方法返回一个具体的 ServiceProrivder, 那么 WebHostBuilder 将不会利用 ServiceCollection 来创建新的 ServiceProvider, 而是直接使用这个返回的 ServiceProvider 来传递到 Startup 的 Configure 方法以供使用. 我们后面会基于这个特性使用其他的 IoC 框架进行扩展替换.
这是 WebHost 调用 Startup 类的 Configure 方法创建管道的过程
- public void Initialize()
- {
- _startup = _hostingServiceProvider.GetService<IStartup>();
- _applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
- EnsureServer();
- var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>();
- var builder = builderFactory.CreateBuilder(Server.Features);
- builder.ApplicationServices = _applicationServices;
- var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>();
- Action<IApplicationBuilder> configure = _startup.Configure;
- foreach (var filter in startupFilters.Reverse())
- {
- configure = filter.Configure(configure);
- }
- configure(builder);
- this._application = builder.Build();
- }
在这里我们不再深究一个完整的流程的每个阶段, 后面源码分析的时候会结合整个流程展示.
来源: https://www.cnblogs.com/lex-wu/p/10739517.html