引言
Inversion of Control,简称IOC,即控制反转。记得当初刚实习的时候公司的带我的人和我提到过IOC这个概念,当初完全不知道是 啥东西。后来有幸写了半年Java,SpringBoot里面业务开发随处可见IOC。再后来我写.Net Core用到的第一个框架Blog.Core项目,它里 面IRepository与Repository和IServices与Services,这种解耦的程度单说它贯彻依赖倒置原则是非常nice的!.NetCore时代更加注 重面向接口编程,并且它内置轻量型的IOC容器可帮助我们灵活的进行开发。
依赖注入
Dependency Injection,何为依赖注入?由容器动态的将对象依赖的资源注入到对象之中。假设容器在构造对象A时,对象A的构造依赖对象B、对象C、对象D这些参数,容器会将这些依赖关系自动构造好,最大限度的完成程序的解耦。依赖注入(Dependency Injection,简称DI)就是构造A对象时,需要依赖B对象,那么就先构造B对象作为参数传递到A对象,这种对象初始化并注入的技术就叫做依赖注入。
.NetCore本身就集成了一个轻量型的IOC容器,我们可以把程序中的抽象(Interface)或业务类根据需要的生命周期配置到容器中。他不是一次把所有的实例都构造出来,当你在用的时候他才会去构造实例!.NetCore内置的IOC容器只支持构造函数注入!
如下三种生命周期的注入:
Singleton
:在第一次被请求的时候被创建,对象的构造函数只会执行一次然后一直会存在内存中之后就一直使用这一个实例。如果在多线程中使用了Singleton,要考虑线程安全的问题,保证它不会有冲突。
Scoped
:一个请求只创建这一个实例,请求会被当成一个范围,也就是说单个请求对象的构造函数只会执行一次,同一次请求内注入多次也用的是同一个对象。假如一个请求会穿透应用层、领域层、基础设施层等等各层,在穿层的过程中肯定会有同一个类的多次注入,那这些多次注入在这个作用域下维持的就是单例。例如工作单元模式就可以借助这种模式的生命周期来实现,像EF Core的DbContext上下文就被注册为作用域服务。
Transient
:每次请求时都会创建一个新的实例,只要注入一次,构造函数就会执行一次即实例化一次。Scoped、Transient的区别是你在同一个上下文中是否期望使用同一个实例,如果是,用Scoped,反之则使用Transient。
😊接下来我们来看下.Net Core中相关IOC核心源码😊
IOC源码
ServiceDescriptor
这个类是用来描述服务注册时的服务类型、实例类型、实现类型、生命周期等信息。就如同他本身的描述:Describes a service with its service type, implementation, and lifetime.
DI容器ServiceProvider之所以能够根据我们给定的服务类型(一般是一个接口类型)提供一个能够开箱即用的服务实例,是因为我们预先注册了相应的服务描述信息,就是说ServiceDescriptor为容器提供了正确的服务信息以供容器选择对应的实例。
这个类一共有四个构造函数,本质其实就是给描述具体注册的Lifetime、ServiceType、ImplementationType、ImplementationInstance、ImplementationFactory赋值。请看源码:
这里的话只列举其中的一个构造函数,因为我发现在文章中源码不能罗列的太多,不然让人看得嫌烦😅
下面这个构造函数需要两个参数,分别是服务元素的类型,服务元素实例,默认是单例的,其它的几个构造函数都与其很相仿。
/// <summary>
/// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="instance"/>
/// as a <see cref="ServiceLifetime.Singleton"/>.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the service.</param>
/// <param name="instance">The instance implementing the service.</param>
public ServiceDescriptor(
Type serviceType,
object instance)
: this(serviceType, ServiceLifetime.Singleton)
{
if (serviceType == null)
{
throw new ArgumentNullException(nameof(serviceType));
}
if (instance == null)
{
throw new ArgumentNullException(nameof(instance));
}
ImplementationInstance = instance;
}
我们再来看下它里面几个重要的函数:
①Describe()
函数,可以看到这个函数也是用来生成ServiceDescriptor
类的,它们分别对应上面的构造函数,也就是说为实例化ServiceDescriptor
提供另外一种方式。源码如下:
private static ServiceDescriptor Describe<TService, TImplementation>(ServiceLifetime lifetime)
where TService : class
where TImplementation : class, TService
{
return Describe(
typeof(TService),
typeof(TImplementation),
lifetime: lifetime);
}
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="serviceType"/>, <paramref name="implementationType"/>,
/// and <paramref name="lifetime"/>.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="implementationType">The type of the implementation.</param>
/// <param name="lifetime">The lifetime of the service.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Describe(Type serviceType, Type implementationType, ServiceLifetime lifetime)
{
return new ServiceDescriptor(serviceType, implementationType, lifetime);
}
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="serviceType"/>, <paramref name="implementationFactory"/>,
/// and <paramref name="lifetime"/>.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
/// <param name="lifetime">The lifetime of the service.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Describe(Type serviceType, Func<IServiceProvider, object> implementationFactory, ServiceLifetime lifetime)
{
return new ServiceDescriptor(serviceType, implementationFactory, lifetime);
}
②Singleton()
函数,这个函数一共有七个重载,我只贴出其中三个方法,其它几个都差不多,总之就是一句话用于生成单例化的ServiceDescriptor
类。源码如下:
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
/// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <typeparam name="TImplementation">The type of the implementation.</typeparam>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Singleton<TService, TImplementation>()
where TService : class
where TImplementation : class, TService
{
return Describe<TService, TImplementation>(ServiceLifetime.Singleton);
}
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="service"/> and <paramref name="implementationType"/>
/// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
/// </summary>
/// <param name="service">The type of the service.</param>
/// <param name="implementationType">The type of the implementation.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Singleton(Type service, Type implementationType)
{
if (service == null)
{
throw new ArgumentNullException(nameof(service));
}
if (implementationType == null)
{
throw new ArgumentNullException(nameof(implementationType));
}
return Describe(service, implementationType, ServiceLifetime.Singleton);
}
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="serviceType"/>, <paramref name="implementationInstance"/>,
/// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="implementationInstance">The instance of the implementation.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Singleton(
Type serviceType,
object implementationInstance)
{
if (serviceType == null)
{
throw new ArgumentNullException(nameof(serviceType));
}
if (implementationInstance == null)
{
throw new ArgumentNullException(nameof(implementationInstance));
}
return new ServiceDescriptor(serviceType, implementationInstance);
}
③Scoped()
函数,这个函数有五个重载,其实他内部还是调用Describe()
方法来生成作用域的ServiceDescriptor
类。源码如下:
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
/// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <typeparam name="TImplementation">The type of the implementation.</typeparam>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Scoped<TService, TImplementation>()
where TService : class
where TImplementation : class, TService
{
return Describe<TService, TImplementation>(ServiceLifetime.Scoped);
}
/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="service"/> and <paramref name="implementationType"/>
/// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
/// <param name="service">The type of the service.</param>
/// <param name="implementationType">The type of the implementation.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Scoped(Type service, Type implementationType)
{
return Describe(service, implementationType, ServiceLifetime.Scoped);
}
通过Scoped()
方法我们可以这样注册:
services.Add(ServiceDescriptor.Scoped<IPersonService, PersonService>());
//services.Add(ServiceDescriptor.Scoped(typeof(IPersonService),typeof(PersonService)));
//或
services.Add(ServiceDescriptor.Transient<IPersonService, PersonService>());
//services.Add(ServiceDescriptor.Transient(typeof(IPersonService), typeof(P