首页 技术 正文
技术 2022年11月15日
0 收藏 792 点赞 2,314 浏览 8721 个字

相关文章:

深入理解net core中的依赖注入、Singleton、Scoped、Transient(一)

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

深入理解net core中的依赖注入、Singleton、Scoped、Transient(三)

深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)

在上一节的学习中,我们已经知道了通过 IServiceCollection 拓展方法创建 IServiceProvider 默认的是一个类型为 ServiceProvider 对象,并且实际提供创建对象功能的是它的内部为类型为 IServiceProviderEngine 对象,实际上关于 IServiceProvider 的架构比我们想象的还要复杂的多,一个是根容器的概念,另一个就是使用编译时引擎(CompliedServiceProviderEngine)动态构建表达式树,提高了创建实例的效率。

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

容器、引擎和根容器

在这张类图中,有三个核心接口,IServiceProvider 表示容器,具备提供对象功能,IServiceScope 代表一个具有范围的节点容器,而 IServiceProviderEngine 是提供对象核心接口,具有一个根容器,每次创建对象的时候都会带上具有范围的节点容器。关于容器和引擎这两个概念如何判断呢?凡是实现了 IServiceProvider 的都可以称为容器,同样的,凡是实现了 IServiceProviderEngine 的都可以称为引擎,引擎仍然是一个容器,实际上,上图中所有的类型都是一个容器,因为他们都直接或者间接实现了 IServiceProvider 接口,然而最终负责创建服务实例的必然是一个引擎!

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

public interface IServiceProvider
{
object GetService(Type serviceType);
}
public interface IServiceScope : IDisposable
{
IServiceProvider ServiceProvider { get; }
}
internal interface IServiceProviderEngine : IDisposable, IServiceProvider
{
IServiceScope RootScope { get; }
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

ServiceProviderEngineScope

IServiceScope 的默认实现是 ServiceProviderEngineScope,ResolvedServices 存储已经实例化过的生命周期为 Scoped 的对象,_disposables 存储通过该根创建的所有实例类型(如果该类型实现了 IDisposable 接口),在调用 Dispose 方法时会释放 _disposables 中的对象,同时清空 ResolvedServices 中的实例。

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
{
private List<IDisposable> _disposables = new List<IDisposable>();
public ServiceProviderEngineScope(ServiceProviderEngine engine)
{
Engine = engine;
} internal Dictionary<object, object> ResolvedServices { get; } = new Dictionary<object, object>();
public ServiceProviderEngine Engine { get; }
public object GetService(Type serviceType)
{
return Engine.GetService(serviceType, this);
}
public IServiceProvider ServiceProvider => this;
//省略了一些代码
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

ServiceProviderEngineScope 总在引擎被创建的时候初始化,并且在 GetService 方法中,传递的根容器正是这个 Root,所以根容器一般情况不会更改,然而我们可以 CreateScope 方法(来自 IServiceScopeFactory 接口)来创建一个新的根容器(实际上是一个新的节点),实际上到这里可能还是很难理解这个作用域是如何形成的,没关系,后面还会介绍!

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
{
protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
Root = new ServiceProviderEngineScope(this);
}
   public object GetService(Type serviceType) => GetService(serviceType, Root);
public ServiceProviderEngineScope Root { get; }
public IServiceScope CreateScope()
{
return new ServiceProviderEngineScope(this);
}
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

默认的容器 ServiceProvider

ServiceProviderOptions

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

public static class ServiceCollectionContainerBuilderExtensions
{
public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
{
return BuildServiceProvider(services, ServiceProviderOptions.Default);
}
public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{
return new ServiceProvider(services, options);
}
}
public class ServiceProviderOptions
{
internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions();
public bool ValidateScopes { get; set; }
internal ServiceProviderMode Mode { get; set; } = ServiceProviderMode.Dynamic;
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

我们知道在 IServiceCollection 的拓展方法 BuildServiceProvider 最终返回的是一个 ServiceProvider,由于默认的 ServiceProviderMode 是 Dynamic,所以默认情况下,提供服务的是一个 DynamicServiceProviderEngine 对象,然而它与 CompiledServiceProviderEngine 唯一的区别就是抽象方法 RealizeService 的实现,前者提供真正的创建对象的方法,而后者将前者提供的创建对象的方法翻译成表达式树。

ServiceProvider

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
{
private readonly IServiceProviderEngine _engine; private readonly CallSiteValidator _callSiteValidator; internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
IServiceProviderEngineCallback callback = null;
if (options.ValidateScopes)
{
callback = this;
_callSiteValidator = new CallSiteValidator();
}
switch (options.Mode)
{
case ServiceProviderMode.Dynamic:
_engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Runtime:
_engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Compiled:
_engine = new CompiledServiceProviderEngine(serviceDescriptors, callback);
break;
default:
throw new ArgumentOutOfRangeException(nameof(options.Mode));
}
}
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

因为 ServiceProviderOptions.Default 提供的参数中 ValidateScoped 默认值是 False,所以这里不打算介绍 IServiceProviderEngineCallback 以及 CallSiteValidator 这两个类型(和服务实例对象的创建有关,后续介绍)。根据参数 option 的 Mode 为 Dynamic,创建了一个类型为 DynamicServiceProviderEngine 的引擎,实际上该引擎是如何创建对象是后续要讲的,这里我们只关注它的创建过程,所以我们又来到了 ServiceProviderEngine 的构造函数。

ServiceProviderEngine

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
{
protected abstract Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite); internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; } =
new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>(); private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor; protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
_createServiceAccessor = CreateServiceAccessor;
_callback = callback; Root = new ServiceProviderEngineScope(this);
RuntimeResolver = new CallSiteRuntimeResolver();
ExpressionBuilder = new CallSiteExpressionBuilder(RuntimeResolver, this, Root);
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
} private readonly IServiceProviderEngineCallback _callback;
internal CallSiteFactory CallSiteFactory { get; }
protected CallSiteRuntimeResolver RuntimeResolver { get; }
protected CallSiteExpressionBuilder ExpressionBuilder { get; }
public ServiceProviderEngineScope Root { get; }
public IServiceScope RootScope => Root; private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
{
var callSite = CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
_callback?.OnCreate(callSite);
return RealizeService(callSite);
} return _ => null;
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

这是一个抽象类,还记得我们前面提起过得 IServiceCallSite 吗?它是创建服务实例的依据,虽然还没有得到证实,但是我们要坚信!然后我们看抽象方法 RealizeService,它是一个方法,提供一个委托,该委托接受一个根容器,然后返回一个实例对象,可能有点绕,简而言之这个抽象方法提供一个方法,该方法可以实现服务实例的创建!

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
public DynamicServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
{
} protected override Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite)
{
var callCount = 0;
return scope =>
{
if (Interlocked.Increment(ref callCount) == 2)
{
Task.Run(() => base.RealizeService(callSite));
}
return RuntimeResolver.Resolve(callSite, scope);
};
}
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

如果我们对该抽象方法返回的委托理解了,那也会很容易理解字典 RealizedServices,和那个委托一样,这个字典存储的是每个服务类型的创建实例的方法,同样的,委托 _createServiceAccessor 也很好理解。关于 CallSiteRuntimeResolver,这里只需要知道在 DynamicServiceProviderEngine 实现的 RealizeService 方法中,最后返回的委托是根据它来解析 IServiceCallSite 来创建实例的!CallSiteExpressionBuilder 这个类型是在 CompiledServiceProviderEngine中实现将创建实例的过程构建成表达式树的,详细过程后续讲,但是这里需要知道对于同一个服务,创建其实例的过程应当总是一致的,而这个过程就保存在 RealizedServices 中,而实际创建实例的过程在 DynamicServiceProviderEngine 中,我们在 DynamicServiceProviderEngine 的 RealizeService 方法中发现,如果是第二次创建该实例,则会调用父类 CompiledServiceProviderEngine 的 RealizeService 方法,并且它是以异步方式执行的,尽管如此,最后创建实例的方法仍然是 DynamicServiceProviderEngine 提供的委托,然而 CompiledServiceProviderEngine 的 RealizeService 方法做了些什么呢?

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

internal class CompiledServiceProviderEngine : ServiceProviderEngine
{
public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
{
} protected override Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite)
{
var realizedService = ExpressionBuilder.Build(callSite);
RealizedServices[callSite.ServiceType] = realizedService;
return realizedService;
}
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

实际上这里返回的 realizedService 永远都不会得到调用(由于它返回的是一个委托,这里的不会调用不是指委托不会调用,这里的永远不会调用是指不会简单的通过调用该方法获取它的返回值),但是这个委托却永远的替换了 RealizedServices 中的某个委托(采用了表达式树重新构建了创建实例的委托),而新的以表达式树构建的委托是如何地调调用的呢?

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
{
var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor);
_callback?.OnResolve(serviceType, serviceProviderEngineScope);
return realizedService.Invoke(serviceProviderEngineScope);
}

深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

我们看到在 ServiceProviderEngine 的 GetService 方法中,只要 RealizedServices 中已经存在该服务的创建实例的委托就不会通过 CreateServiceAccessor 再去调用抽象方法获取委托,也就是说被 CompiledServiceProviderEngine 执行它自己的 RealizeService 方法后,以后创建该服务的实例对象总是通过表达式树创建的。

小结

在这一节中,我们学习了容器创建过程中的一些核心类型,然而最核心的依然在 ServiceProviderEngine 这个抽象类中,尽管提供了抽象方法 RealizeService 允许子类提供创建实例的委托,但是创建实例的具体逻辑依然有它自己的 CallSiteRuntimeResolver 提供,再加上创建实例的方法始终都是通过委托提供的,所以使得 DynamicServiceProviderEngine 和 CompileServiceProviderEngine 这两个类非常的简洁,但是依然对 DynamicServiceProviderEngine 是如何使用 CallSiteRuntimeResolver 创建实例的,CompileServiceProviderEngine 又是如何构建表达式树的,作用域又是如何形成的,因为这些都和 IServiceCallSite 有离不开的关系。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,028
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,518
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,365
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,146
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,780
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,857