Dependency Inject 概述
依赖注入(
DI
)是一种编程模式,指将原本本类中依赖的对象通过外部传入,以达到解耦的目的,因为创建对象的控制权发生了变换(由原本是当前类来控制对象如何创建,已经如何销毁). 这样会引发一些问题, 比如对象应该在何时被创建,何时销毁(也就是依赖对象的生命周期).
IOC 与 DI
引用 ASP.NET Core 框架解密 中的一段话, Ioc 主要体现了这样一种思想: 通过将一组通用流程的控制权从应用转移到框架之中以实现对流程的复用,并按照好莱坞法则实现应用程序的代码与框架之间的交互. 我们可以采用若干设计模式以不同的方式实现
Ioc
如模板方法, 工厂方法和抽象工厂, 下面介绍一种更具有价值的Ioc模式:依赖注入(DI). 这样看DI
只是Ioc
的一种实现方式, Ioc 是从更宏观的角度去考虑应用程序和框架应该怎样去设计, 而为DI是解决对象依赖的具体问题而生的
Microsoft.Extensions.DependencyInjection
微软为我们提供的
DI
类库位于Microsoft.Extensions.DependencyInjection
, 和Microsoft.Extensions.DependencyInjection.Abstractions
这个类库里面,其中 后缀为Abstractions
的里面提供了相应的接口生命,而实现则在DependencyInjection
, 我们看一段简单的代码,来了解下使用方式.
using Microsoft.Extensions.DependencyInjection;
using System;
namespace Demo
{
internal class Program
{
static void Main(string[] args)
{
var serviceProviderFactory = new DefaultServiceProviderFactory();
var services = new ServiceCollection();
services.AddScoped<ILogger, Logger>();
var serviceProvider = serviceProviderFactory.CreateServiceProvider(services);
var logger = serviceProvider.GetRequiredService<ILogger>();
logger.Log();
Console.ReadKey();
}
}
public interface ILogger
{
void Log();
}
public class Logger : ILogger
{
public void Log()
{
Console.WriteLine("logger");
}
}
}
程序正常输出
logger
上述代码中
- 先是创建了一个
DefaultServiceProviderFactory
的对象, - 创建了一个
ServiceCollection
的对象services
- 将我们需要依赖的对象
Logger
添加到services
对象中, 并对外提供一个接口Ilogger
serviceProviderFactory
该对象为我们提供了一个方法CreateServiceProvider()
用于创建服务提供者, 接受一个ServiceCollection
对象作为参数- 通过
serviceProvider
的GetRequiredService()
方法 获取ILogger
接口 - 调用
ILogger
接口的Log()
方法,在控制台上打印log
上面是使用依赖注入DI
的基本使用方法. 我们使用的 AddScoped()
方法是以 Scoped
方式将 Logger
加入到了 DI
容器中, 这里的容器指的是 ServiceCollection
. 下面我们看下一共有几种生命周期的方式
AddSingleton()
以单例的方式将类型注入到容器中, 该类型的对象在整个程序中是唯一的AddScoped()
在一个范围内保持从容器中获取某一个类型的对象是唯一的AddTransient()
每次从容器中获取某一个类型的对象时,都获取新对象
AddSingleton()
,AddTransient()
这两种方式都好理解,相对于我们传统的创建对象的方式,Singleton
是单例模式,Transient
是每次都会new
一个新的对象. 那么Scoped
中 这个范围是什么呢, 我们来看看
public static IServiceCollection AddScoped(
this IServiceCollection services,
Type serviceType,
Type implementationType)
{
//...省略若干代码
return Add(services, serviceType, implementationType, ServiceLifetime.Scoped);
}
private static IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
Type implementationType,
ServiceLifetime lifetime)
{
var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
return collection;
}
IServiceCollection
IServiceCollection
是实现了IList<ServiceDescriptor>
接口的, 所以本质上他是包裹了ServiceDescriptor
的集合,向IServiceCollection
添加类型注册, 实际上就是添加ServiceDescriptor
ServiceDescriptor
ServiceDescriptor
用来描述一个服务注册时候的信息,我们可以手动调用IServiceCollection
的Add()
方法向容器中添加ServiceDescriptor
对象. 下面是ServiceDescriptor
的部分代码
public class ServiceDescriptor
{
//... 省略若干代码
public ServiceLifetime Lifetime { get; }
public Type ServiceType { get; }
public Type ImplementationType { get; }
public object ImplementationInstance { get; }
public Func<IServiceProvider, object> ImplementationFactory { get; }
//... 省略若干代码
}
从上面的代码可以看出,
Lifetime
表示生命周期ServiceType
表示注册服务的类型ImplementationType
表示服务注册类型实现的类型ImplementationInstance
表示服务注册类型实现的对象,例如:直接注入自己创建的对象.ImplementationFactory
表示服务实现的工厂,使用一个委托类型Func<IServiceProvider, object>
来表示
ServiceDescriptor
对象还提供了很多静态方法,方便我们构造ServiceDescriptor
对象,代码如下:
public class ServiceDescriptor
{
public static ServiceDescriptor Scoped<TService, TImplementation>()
where TService : class
where TImplementation : class, TService
{
// ...
}
public static ServiceDescriptor Singleton<TService, TImplementation>()
where TService : class
where TImplementation : class, TService
{
// ...
}
public static ServiceDescriptor Transient(Type service, Func<IServiceProvider, object> implementationFactory)
{
// ...
}
}
ServiceProvider
ServiceProvider
继承自IServiceProvider
实现了GetService()
方法, 但真正提供提供获取服务对象的并不是他, 他只是一个Enging
的工厂,GetService()
方法调用的也是Enging
的GetService()
方法, 默认使用的是DynamicServiceProviderEngine
, 他是ServiceProviderEngine
的子类
ServiceProviderEngine
ServiceProviderEngine
也实现了IServiceProvider
接口, 作为跟容器, 封装着一个名为Root
的ServiceProviderEngineScope
对象,
internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
{
//... 省略若干代码
public ServiceProviderEngineScope Root { get; }
public IServiceScope RootScope => Root;
protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
//... 省略若干代码
Root = new ServiceProviderEngineScope(this);
//... 省略若干代码
}
public object GetService(Type serviceType) => GetService(serviceType, Root);
public IServiceScope CreateScope()
{
if (_disposed)
{
ThrowHelper.ThrowObjectDisposedException();
}
return new ServiceProviderEngineScope(this);
}
//... 省略若干代码
}
ServiceProviderEngineScope
ServiceProviderEngineScope
对象维护着 以下两个关键的字段_disposables
字段, 当调用GetService()
获取一个对象的时候, 如果这个对象实现了IDisposable
接口,则该对象会被添加到_disposables
里面. 当自身的Dispose()
方法被调用时, 他会循环调用_disposables
里对象的Dispose()
方法 以释放依赖 scope 范围内的对象