hello,大家好,今天依然是橙子老哥的分享时间,希望大家一起学习,一起进步。
欢迎加入.net意社区,第一时间了解我们的动态
官方地址:https://ccnetcore.com
微信公众号:搜索 意.Net
添加橙子老哥微信:chengzilaoge520
最近有小伙伴问我,依赖注入天天用,无非就是构造函数递归找构造函数,这有什么难的?可是真正问到细节,却又一知半解,做一个成熟稳定的IOC真的很不容易,需要考虑并发、循环依赖、缓存、泛型、作用域等等因素
今天我们就来看看.NetCore内置的IOC容器,具体源码细节是如何实现的?由于IOC的篇幅较长,橙子老哥带大家从外层一层一层揭开依赖注入的面纱
1、使用
我们需要先安装:Microsoft.Extensions.DependencyInjection
包,默认是带了抽象包,没有实现,我们是执行不了BuildServiceProvider
的扩展方法的
以下是控制台使用,我们讲IService加入到容器,并在build之后,在从容器中获取出来
using Microsoft.Extensions.DependencyInjection;
var services=newServiceCollection();
services.AddTransient<IService,MyService>();
var serviceProvider=services.BuildServiceProvider();
varmy=serviceProvider.GetRequiredService<IService>();
my.DoWork();
publicinterfaceIService
{
void DoWork();
}
publicclassMyService:IService
{
public void DoWork()
{
// 实现功能
Console.WriteLine("你好");
}
}
以上的使用代码,相信大家早已经了如指掌,同样我这里没必要讲那些基础使用以及概念了
为什么要使用IOC,IOC的生命周期,IOC的好处。。。。。这些留给大家仔细思考吧~
上面的示例的流程,我们分为三步
1. services.AddTransient<IService,MyService>(); 将服务添加进服务容器中
2. BuildServiceProvider 构建容器
3. 通过GetRequiredService从容器中获取到对应的服务
services.AddTransient<IService,MyService>()
往里面看看
ServiceDescriptor serviceDescriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(serviceDescriptor);
这3步主要是用到了3个核心对象
1. ServiceCollection (服务容器,我们的向容器中添加的服务存储在这里)
2. ServiceDescriptor (服务描述者,我们向容器中新增的东西会转换成这个)
3. ServiceProvider(服务提供者,通过服务容器构建之后,我们从这里获取对应的服务)
弄清楚了这个,我们再往里面看
2、ServiceCollection 服务容器
我们看看,这个服务容器里面是如何存储我们新增进去的ServiceDescriptor
public interface IServiceCollection : IList<ServiceDescriptor>,
ICollection<ServiceDescriptor>,
IEnumerable<ServiceDescriptor>,
IEnumerable
{
}
emmm,好像就是一个ServiceDescriptor
集合,所以通过扩展方法包几层,ServiceDescriptor
通过集合的add方法就新增进去了
真的没有看错,这个玩意儿,本质上就是一个
ServiceDescriptor
集合
当然,这个集合还做了一步services.BuildServiceProvider();
他是如何进行服务容器的构建的呢?我们往里面看看
public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{
if(services isnull)
{
throw new ArgumentNullException(nameof(services));
}
if(options isnull)
{
throw new ArgumentNullException(nameof(options));
}
return new ServiceProvider(services, options);
}
BuildServiceProvider 是一个扩展方法,目的是通过IServiceCollection
去创建(new)一个ServiceProvider
3、ServiceProvider 服务提供者-创建
ServiceCollection
真的没有什么内容,现在我们看看ServiceProvider
,它主要在我们的流程里面做了两个事情
1. BuildServiceProvider 的时候去new了一个出来
2. 调用GetRequiredService 的时候,从服务容器中取出对应的服务
我们先看看它是如何new出来的
private readonly Func<ServiceIdentifier,ServiceAccessor> _createServiceAccessor;
// Internal for testing
internal ServiceProviderEngine _engine;
private bool _disposed;
private readonly ConcurrentDictionary<ServiceIdentifier,ServiceAccessor> _serviceAccessors;
internal CallSiteFactory CallSiteFactory{get;}
internal ServiceProvider EngineScopeRoot{get;}
//构造方法
internal ServiceProvider(ICollection<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
// note that Root needs to be set before calling GetEngine(), because the engine may need to access Root
//设置一个根节点的作用域,控制对象生命周期
Root=new ServiceProvider EngineScope(this, isRootScope:true);
//获取到对应的引擎
_engine =GetEngine();
//存储了一个创建服务的委托
_createServiceAccessor =CreateServiceAccessor;
//对上面的委托以ServiceIdentifier为key 做了一个缓存
_serviceAccessors =new ConcurrentDictionary<ServiceIdentifier,ServiceAccessor>();
//CallSiteFactory 工厂,一个核心对象,用于创建服务
CallSiteFactory=new CallSiteFactory(serviceDescriptors);
// The list of built in services that aren't part of the list of service descriptors
// keep this in sync with CallSiteFactory.IsService
//将固定几个接口加入到CallSiteFactory 工厂中
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceProvider)),new ServiceProviderCallSite());
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceScopeFactory)),new ConstantCallSite(typeof(IServiceScopeFactory),Root));
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceProviderIsService)),new ConstantCallSite(typeof(IServiceProviderIsService),CallSiteFactory));
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceProviderIsKeyedService)),new ConstantCallSite(typeof(IServiceProviderIsKeyedService),CallSiteFactory));
//判断是否要校验作用域
if(options.ValidateScopes)
{
_callSiteValidator =new CallSiteValidator();
}
//是否就在build的时候进行校验循环依赖等问题
if(options.ValidateOnBuild)
{
List<Exception>? exceptions =null;
foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors)
{
try
{
ValidateService(serviceDescriptor);
}
catch(Exception e)
{
exceptions ??=new List<Exception>();
exceptions.Add(e);
}
}
if(exceptions !=null)
{
throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray());
}
}
DependencyInjectionEventSource.Log.ServiceProviderBuilt(this);
}
这里在构造函数中做了很多事情
我们来分析一下
_engine = GetEngine();
private ServiceProviderEngine GetEngine()
{
ServiceProviderEngine engine;
#if NETFRAMEWORK || NETSTANDARD2_0
engine =CreateDynamicEngine();
#else
if(RuntimeFeature.IsDynamicCodeCompiled&&!DisableDynamicEngine)
{
engine =CreateDynamicEngine();
}
else
{
// Don't try to compile Expressions/IL if they are going to get interpreted
engine =RuntimeServiceProviderEngine.Instance;
}
#endif
return engine;
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "CreateDynamicEngine won't be called when using NativeAOT.")]// see also https://github.com/dotnet/linker/issues/2715
ServiceProviderEngine CreateDynamicEngine()=>newDynamicServiceProviderEngine(this);
}
这里根据环境的不一样,使用不同的引擎进行构造,这里我们走的是RuntimeServiceProviderEngine.Instance
它是ServiceProviderEngine
的派生类,其中只有一个方法RealizeService
,引擎用于实现的服务,是一个委托,这里走的是CallSiteRuntimeResolver.Instance
,到这里我们先打住一下(后续会对应有核心对象),我们暂时知道,我们去根据环境获取到对应创建服务的引擎,GetEngine,获取到运行时引擎, RuntimeServiceProviderEngine.Instance,这里面又使用CallSiteRuntimeResolver.Instance去创建CallSiteRuntimeResolver
类,具体引擎去解析者是通过CallSiteRuntimeResolver
完成的
internal sealedclassRuntimeServiceProviderEngine:ServiceProviderEngine
{
public static RuntimeServiceProvider EngineInstance{get;}=new RuntimeServiceProviderEngine();
private RuntimeServiceProviderEngine()
{
}
public override Func<ServiceProviderEngineScope,object?>RealizeService(
ServiceCallSite callSite)
{
return (Func<ServiceProviderEngineScope,object>)(scope =>CallSiteRuntimeResolver.Instance.Resolve(callSite, scope));
}
}
internal sealed class CallSiteRuntimeResolver:CallSiteVisitor<RuntimeResolverContext,object?>
{
public static CallSiteRuntimeResolverInstance{get;}=new CallSiteRuntimeResolver();
}
我们回到ServiceProvider 继续看,CreateServiceAccessor
这个里面做了什么
private ServiceAccessor CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
{
//通过CallSiteFactory 通过服务的身份证去获取对应是CallSite
ServiceCallSite? callSite =CallSiteFactory.GetCallSite(serviceIdentifier,newCallSiteChain());
if(callSite !=null)
{
DependencyInjectionEventSource.Log.CallSiteBuilt(this, serviceIdentifier.ServiceType, callSite);
OnCreate(callSite);
//如果通过CallSiteFactory获取到对应的CallSite,一口气塞给引擎去处理
Func<ServiceProviderEngineScope,object?> realizedService = _engine.RealizeService(callSite);
return new ServiceAccessor{CallSite= callSite,RealizedService= realizedService };
}
return new ServiceAccessor{CallSite= callSite,RealizedService= _ =>null};
}
这里我们注意两个核心对象,CallSiteFactory
(获取对应的ServiceCallSite)和ServiceProviderEngine
(上面的容器引擎) 这个容器引擎,刚好又回到最前面的容器引擎的RealizeService
实现方法,接到上面的引擎最后执行的是CallSiteRuntimeResolver
运行时CallSite解析者
这里透露着两个信息,我们一定要清楚,不然很容易被这些核心对象给转晕
1. CallSiteFactory callsite工厂是为了创建ServiceCallSite
2. ServiceCallSite 是用于存储服务访问配置,通过它进行封装所需要实例化的信息
3. 有了ServiceCallSite 之后,再将它交给对应的引擎去解析
OK,到这里又会发现,多了很多概念和很多核心对象,之后我们会一一介绍,我们再回到构建的时候
这里还做了最后一步
if (options.ValidateOnBuild)
{
ValidateService(serviceDescriptor);
}
如果我们在构建服务容器的时候,传入了option,它还会去校验循环依赖
var serviceProvider=services.BuildServiceProvider(new ServiceProviderOptions(){ValidateOnBuild=true});
//如果开启了ValidateOnBuild ,就执行下面的代码
private void ValidateService(ServiceDescriptor descriptor)
{
if(descriptor.ServiceType.IsGenericType&&!descriptor.ServiceType.IsConstructedGenericType)
{
return;
}
try
{
ServiceCallSite? callSite =CallSiteFactory.GetCallSite(descriptor,newCallSiteChain());
if(callSite !=null)
{
OnCreate(callSite);
}
}
catch(Exception e)
{
throw new InvalidOperationException($"Error while validating the service descriptor '{descriptor}': {e.Message}", e);
}
}
我们先去遍历了容器中所有的ServiceDescriptor
,然后通过CallSiteFactory去获取对应的服务
这里使用一个try包住了 ServiceCallSite? callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain());
方法,如果CallSiteFactory内部获取不到报错了,那直接抛出异常
这个 CallSiteFactory 到底是何方神圣,好像获取服务相关,每次都有它,我们后续在玩一玩它
4、ServiceProvider 服务提供者-获取服务
GetRequiredService
这里也是扩展方法,一层包一层的,最终,走到以下内容
internal object? GetService(ServiceIdentifier serviceIdentifier,ServiceProviderEngineScope serviceProviderEngineScope)
{
if(_disposed)
{
ThrowHelper.ThrowObjectDisposedException();
}
ServiceAccessor serviceAccessor = _serviceAccessors.GetOrAdd(serviceIdentifier, _createServiceAccessor);
OnResolve(serviceAccessor.CallSite, serviceProviderEngineScope);
DependencyInjectionEventSource.Log.ServiceResolved(this, serviceIdentifier.ServiceType);
object? result = serviceAccessor.RealizedService?.Invoke(serviceProviderEngineScope);
System.Diagnostics.Debug.Assert(result isnull||CallSiteFactory.IsService(serviceIdentifier));
return result;
}
_serviceAccessors 前面我们说过,它只是一个 private readonly ConcurrentDictionary<ServiceIdentifier, ServiceAccessor> _serviceAccessors;
线程安全字典,用于将serviceIdentifier
服务身份证作为key,进行缓存我们的CreateServiceAccessor
方法
CreateServiceAccessor
是用于创建对应的服务的过程,用ServiceIdentifier
进行缓存,每种ServiceIdentifier
对应一种创建服务的过程
这里只是执行了一步serviceAccessor.RealizedService?.Invoke(serviceProviderEngineScope);
,通过serviceAccessor
和引擎去解析ServiceIdentifier
中的服务
这里又一个核心对象,ServiceAccessor
private sealedclassServiceAccessor
{
//存储一个服务配置Callsite
public ServiceCallSite? CallSite {get;set;}
//存储一个通过Root服务提供者引擎解析到服务实例的委托
public Func<ServiceProviderEngineScope,object?>? RealizedService {get;set;}
}
这里我们在构造函数的时候,就已经给它赋值了
//ServiceProvider 构建的时候
//存储了一个创建服务的委托
_createServiceAccessor = CreateServiceAccessor;
private ServiceAccessor CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
{
ServiceCallSite? callSite =CallSiteFactory.GetCallSite(serviceIdentifier,newCallSiteChain());
if(callSite !=null)
{
DependencyInjectionEventSource.Log.CallSiteBuilt(this, serviceIdentifier.ServiceType, callSite);
OnCreate(callSite);
// Optimize singleton case
if(callSite.Cache.Location==CallSiteResultCacheLocation.Root)
{
object? value=CallSiteRuntimeResolver.Instance.Resolve(callSite,Root);
return new ServiceAccessor{CallSite= callSite,RealizedService= scope =>value};
}
Func<ServiceProviderEngineScope,object?> realizedService = _engine.RealizeService(callSite);
return new ServiceAccessor{CallSite= callSite,RealizedService= realizedService };
}
returnnewServiceAccessor{CallSite= callSite,RealizedService= _ =>null};
}
好家伙,兜兜转转又回来了这里,又是这个CallSiteFactory
!
这回晚上睡觉掀开被窝一看,嚯!又是你
CallSiteFactory
至此,我们只是走完了最外一层,这些大致流程的是清楚的,只是留下很多核心对象没有进行深入,但是也不会太妨碍我们阅读,这其实也是精妙之处,微软将构建引擎、CallSite等对象抽象出来,不着急,关注橙子老哥,一步一步带你深入 (我其实不太喜欢将文章拆分很多个,奈何微软的IOC相对于其他组件来说,难度确实高了很多,所以篇幅有限,也为了让大家更好理解,特意将后续内容拆分多个章节)
.Net意社区,高频发布原创有深度的.Net相关知识内容
与你一起学习,一起进步