1.ServiceCollection(依赖注入的容器)
ServiceCollection:ICollection作为依赖注入的容器,它存在一个List用来存放所有的注入到容器中的类型
这里以注入单例模式执行过程为例为例:
注入流程
注入后的容器
2.ServiceDescriptor(注入服务描述器)
private ServiceDescriptor(Type serviceType, ServiceLifetime lifetime){ this.Lifetime = lifetime; this.ServiceType = serviceType;}//标准的注入public ServiceDescriptor(Type serviceType, Type implementationType, ServiceLifetime lifetime) : this(serviceType, lifetime){ if (serviceType == null) {throw new ArgumentNullException("serviceType");} if (implementationType == null) {throw new ArgumentNullException("implementationType"); } this.ImplementationType = implementationType;}//Singleton模式public ServiceDescriptor(Type serviceType, object instance) : this(serviceType, ServiceLifetime.Singleton) { //校验省略 this.ImplementationInstance = instance;}//工厂模式,通过ServiceProvider的Func注入public ServiceDescriptor(Type serviceType, Func factory, ServiceLifetime lifetime) : this(serviceType, lifetime) {//校验省略 this.ImplementationFactory = factory;}
3.ServiceProvider(实例化器)
var provider = services.BuildServiceProvider();
以Transient实例化详细执行流程如下图:
var orderService = provider.GetService();
Singleton,Scope,Transient三种模式下的产生对象实例的流程如下:
4.IServiceScope
创建作用域,也就是创建子容器
单例模式是在Root容器下的,只能程序停止时释放,Transient模式,每次都会产生新的实例,所以两者应用不多。我们可以使用Scope的实例测试。
1.准备服务类 public interface IOrderService { } public class DisposableOrderService : IOrderService, IDisposable { public void Dispose() { Console.WriteLine($"DisposableOrderService Disposed:{this.GetHashCode()}"); } }2.注入为Scope services.AddScoped(); 3.1调用 [HttpGet] public int Get( [FromServices] IOrderService aaa, [FromServices] IOrderService bbb, [FromServices]IHostApplicationLifetime hostApplicationLifetime, [FromQuery]bool stop = false) { return 1; } 【结果,只会打印一次,被释放的信息,因为aaa,bbb是同一个实例】3.2 新建scope调用 [HttpGet] public int Get( [FromServices] IOrderService aaa, [FromServices] IOrderService bb, [FromServices]IHostApplicationLifetime hostApplicationLifetime, [FromQuery]bool stop = false) { using (IServiceScope scope = HttpContext.RequestServices.CreateScope()) { var service = scope.ServiceProvider.GetService(); } return 1; } 【结果,会打印两次,被释放的信息。因为在scope内,相当于创建了一个子容器,重新创建一个是实例】
5.容器使用注意事项
1.容器会管理释放自己创建的对象,所以我们不要手动创建对象,然后放入容器。如果实现了IDisable接口,容器会帮助我们管理生命周期,调用Dispose方法。
只有Singleton接口可以直接传入一个new 的对象,其他两个接口的工厂模式和类型注入的模式的效果时一样的1.创建的实例由容器控制释放service.AddSignleton();2.实例的生命周期不由容器控制释放service.AddSingleton(new OrderService()));
2.单例是注入到应用程序的根容器(Root)中,根容器是伴随整个应用程序存在的。如果使用根容器获取Transient对象,那么将会永远存在整个应用程序周期中,不会释放。所以不要在跟容器中获取Transient对象
//跟容器是存放单例模式的,如果通过根容器获取临时对象,临时对象是不会被释放的。ApplicationService就是根容器app.ApplicationService.GetService();
3.ServiceCollection支持一个接口多个实现同时注入。
4.如果是在整个类中使用的对象,可以使用构造函数注入,如果仅仅是某个方法使用,那么可以通过属性标签的方式注入[FromService]