.net core IOC 容器实现(四) -- CallSiteRuntimeResolver

这篇具有很好参考价值的文章主要介绍了.net core IOC 容器实现(四) -- CallSiteRuntimeResolver。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上一节聊了一下 CallSite 是怎样生成的,这一节我们来看一下 CallSite 是如何使用的。

入口

先让我们来回顾一下 CreateServiceAccessor 这个方法。

private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType)        
{
    //通过 服务类型 获取 callSite           
    ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());            
    if (callSite != null)           
    {                           
        if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)                
        {                
            //直接解析    
            object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);                                  
        }                       
        return _engine.RealizeService(callSite);            
    }
}

这段代码跟 CallSite 有关的一共有三个地方,分别是 GetCallSiteResolve(callSite,Root)以及 _engine.RealizeService。其中 GetCallSite 是用来生成 CallSite 的(也就是上一节的主要内容),而剩下的两个则是对于 CallSite 的使用,也是这一节的主要内容。

RealizeService

我们先看一下 _engine.RealizeService 方法。

public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{                      
    return scope =>            
    {                
        var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);                       
        return result;            
    };        
}

我们可以发现最终调用的还是 CallSiteRuntimeResolver.Instance.Resolve 这个方法,所以其实归根结底对 CallSite 的调用其实最终就是一个地方,也就是这个 Resolve 方法。

CallSiteRuntimeResolver.Resolve

public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
    // 如果在 root scope 范围里已经有缓存了,直接返回
    if (scope.IsRootScope && callSite.Value is object cached)
    {
        return cached;
    }
    //调用 VisitCallSite 进行解析
    return VisitCallSite(callSite, new RuntimeResolverContext
    {
        Scope = scope
    });
}

VisitCallSite

protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
    switch (callSite.Cache.Location)
    {
        case CallSiteResultCacheLocation.Root:
            return VisitRootCache(callSite, argument);
        case CallSiteResultCacheLocation.Scope:
            return VisitScopeCache(callSite, argument);
        case CallSiteResultCacheLocation.Dispose:
            return VisitDisposeCache(callSite, argument);
        case CallSiteResultCacheLocation.None:
            return VisitNoCache(callSite, argument);
        default:
            throw new ArgumentOutOfRangeException();
    }
}

VisitCallSite 会根据 Location 进行分支处理,Location 是 CallSite 里的一个属性。其中 Root 对应 Singleton,Scope 对应 Scope 生命周期,Dispose 对应 Trasient,None可以先将其理解为Singleton。

VisitRootCache(Single)

protected override object? VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
{
    // Singleton 懒加载 如果有 value 直接返回          
    if (callSite.Value is object value)
    {
        // Value already calculated, return it directly
        return value;
    }

    var lockType = RuntimeResolverLock.Root;
    //在 root 范围进行解析
    ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
    // 锁住 callSite 防止重复生成value

    lock (callSite)
    {
        // Lock the callsite and check if another thread already cached the value
        // 可能其他地方已经生成了,在获取一下看看        
        if (callSite.Value is object callSiteValue)
        {
            return callSiteValue;
        }
        //最终依旧是调用了 VisitCallSiteMain 方法

        object? resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
        {
            Scope = serviceProviderEngine,
            AcquiredLocks = context.AcquiredLocks | lockType
        });
        serviceProviderEngine.CaptureDisposable(resolved);
        //进行缓存
        callSite.Value = resolved;
        return resolved;
    }
}

VisitScopeCache(Scope)

// Check if we are in the situation where scoped service was promoted to singleton
// and we need to lock the root
// Scope 依赖 Singleton
return context.Scope.IsRootScope ?
    VisitRootCache(callSite, context) :
    VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
private object? VisitCache(
    ServiceCallSite callSite, 
    RuntimeResolverContext context, 
    ServiceProviderEngineScope serviceProviderEngine, 
    RuntimeResolverLock lockType)
{
    bool lockTaken = false;
    object sync = serviceProviderEngine.Sync;
    // Dictionary<ServiceCacheKey, object?> ResolvedServices { get; } 缓存
    Dictionary<ServiceCacheKey, object?> resolvedServices = serviceProviderEngine.ResolvedServices;
    // Taking locks only once allows us to fork resolution process
    // on another thread without causing the deadlock because we
    // always know that we are going to wait the other thread to finish before
    // releasing the lock
    // 锁住 sync 对象
    if ((context.AcquiredLocks & lockType) == 0)
    {
        Monitor.Enter(sync, ref lockTaken);
    }
    try
    {
        //获取锁之后
        // Note: This method has already taken lock by the caller for resolution and access synchronization.
        // For scoped: takes a dictionary as both a resolution lock and a dictionary access lock.
        //先访问缓存
        if (resolvedServices.TryGetValue(callSite.Cache.Key, out object? resolved))
        {
            return resolved;
        }
        //解析
        resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
        {
            Scope = serviceProviderEngine,
            AcquiredLocks = context.AcquiredLocks | lockType
        });
        //缓存需要释放的实例
        serviceProviderEngine.CaptureDisposable(resolved);
        //放入缓存
        resolvedServices.Add(callSite.Cache.Key, resolved);
        return resolved;
    }
    finally
    {
        //解锁
        if (lockTaken)
        {
            Monitor.Exit(sync);
        }
    }
}

VisitDisposeCache(Transient)

protected override object? VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)        
{    
    //解析        
    var instance=VisitCallSiteMain(transientCallSite, context);
    return context.Scope.CaptureDisposable(instance);        
}

VisitNoCache(None)

protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
{
    return VisitCallSiteMain(callSite, argument);
}

VisitCallSiteMain

观察以上方法,我们可以发现无论是 VisitRootCache还是VisitScopeCache 等等,最终都是调用 VisitCallSiteMain 这个方法来生成的实例。

protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
    //callSite.kind 是只读属性 ,在 GetCallSite 时确定,根据 CallSite 类型确定(例 ConstantCallSite)
    switch (callSite.Kind)
    {
        case CallSiteKind.Factory:
            return VisitFactory((FactoryCallSite)callSite, argument);
        case CallSiteKind.IEnumerable:
            return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
        case CallSiteKind.Constructor:
            return VisitConstructor((ConstructorCallSite)callSite, argument);
        case CallSiteKind.Constant:
            return VisitConstant((ConstantCallSite)callSite, argument);
        case CallSiteKind.ServiceProvider:
            return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
        default:
            throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
    }
}

VisitConstructor

其中比较复杂的就是这个 VisitConstructor 方法,通过反射来构造实例,主要思路是拿到实例类型的构造函数,然后通过递归(调用VisitCallSite(见本文最上方))准备构造函数所需要的参数,最后调用 invoke 来生成实例。

protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
{
    object?[] parameterValues;
    //获取构造需要使用的参数
    //无参
    if (constructorCallSite.ParameterCallSites.Length == 0)
    {
        parameterValues = Array.Empty<object>();
    }
    //有参
    else
    {
        parameterValues = new object?[constructorCallSite.ParameterCallSites.Length];
        for (int index = 0; index < parameterValues.Length; index++)
        {
            //递归解析 VisitCallSite 见上文
            parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
        }
    }
#if NETFRAMEWORK || NETSTANDARD2_0
            try
            {
                return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
            }
            catch (Exception ex) when (ex.InnerException != null)
            {
                ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                // The above line will always throw, but the compiler requires we throw explicitly.
                throw;
            }
#else
    return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, 
                                                        parameters: parameterValues, culture: null);
#endif
}

VisitFactory

protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
{
    //调用  Factory(Func<IServiceProvider, object> Factory) 委托(委托由开发者实现)
    return factoryCallSite.Factory(context.Scope);
}

VisitIEnumerable

protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
{
    //创建枚举类型的数组
    var array = Array.CreateInstance(
        enumerableCallSite.ItemType,
        enumerableCallSite.ServiceCallSites.Length);                            

    //给数组填充值
    for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
    {
        object? value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
        array.SetValue(value, index);
    }
    return array;
}

VisitConstant

protected override object? VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)        
{            
    //直接返回保存的实例
    return constantCallSite.DefaultValue;        
}

VisitServiceProvider

protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)        
{            
    return context.Scope;        
}

总结

先根据实例的生命周期进行分支判断,接下来根据服务的生成方式进行分支判断。
.net core IOC 容器实现(四) -- CallSiteRuntimeResolver文章来源地址https://www.toymoban.com/news/detail-600637.html

到了这里,关于.net core IOC 容器实现(四) -- CallSiteRuntimeResolver的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • .NET6.0实现IOC容器

    IOC 的作用这里省略…只对如何使用进行说明。 这里使用 .NET6.0 WebAPI 应用 下面是在 program 类中的代码 通过在 Controller 的构造函数中注入 IAuthService 启动后,通过 swagger 发起请求,验证接口。 基本 IOC容器 流程已实现。但是这样存在一个弊端,每个接口和实现都要在 program 中手

    2024年02月10日
    浏览(45)
  • .net core di ioc

    (Dependency Injection,DI)依赖注入,又称依赖关系注入,是一种软件设计模式,也是依赖倒置原则的一种体现。 依赖倒置原则的含义如下 上层模块不依赖下层模块。二者都依赖抽象 抽象不依赖细节 细节依赖抽象 依赖注入原则有别于传统的通过new直接依赖下层模块的形式,

    2024年02月22日
    浏览(34)
  • asp.net core6 webapi 使用反射批量注入接口层和实现接口层的接口的类到ioc中

    IBLL接口层类库 BLL实现接口层类库 program中利用反射批量注入 在控制器中使用构造函数传参就可以调用已经注册的所有是是实现接口的类了的实列了

    2024年02月13日
    浏览(40)
  • 【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入

    前言:在C/S架构上,WPF无疑已经是“桌面一霸”了。在.NET生态环境中,很多小伙伴还在使用Winform开发C/S架构的桌面应用。但是WPF也有很多年的历史了,并且基于MVVM的开发模式,受到了很多开发者的喜爱。 并且随着工业化的进展,以及几年前微软对.NET平台的开源,国内大多

    2024年02月06日
    浏览(63)
  • .Net Core后端架构实战【3-介入IOC控制反转】

    摘要:基于.NET Core 7.0WebApi后端架构实战【2-介入IOC控制反转】  2023/04/09, ASP.NET Core 7.0, VS2022 Dependency Injection,何为依赖注入?由容器动态的将对象依赖的资源注入到对象之中。假设容器在构造对象A时,对象A的构造依赖对象B、对象C、对象D这些参数,容器会将这些依赖关系自

    2024年02月07日
    浏览(43)
  • .NET开源IOC内置容器,生命周期管理与Autofac扩展

    大家好,我是行不更名,坐不改姓的宋晓刚,下面将带领大家从基础小白到高阶的.NET的IOC容器依赖与注入,以及IOC内置容器和生命周期,Autofac的学习,跟上我的步伐进入C#的世界。 微信:15319589104 QQ: 2981345658 文章内容: .NET依赖注入容器的生命周期管理,瞬时生命周期(

    2024年01月21日
    浏览(50)
  • 如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?

    我们知道整个ASP.NET Core建立在以ServiceCollection/ServiceProvider为核心的DI框架上,它甚至提供了扩展点使我们可以与第三方DI框架进行整合。对此比较了解的读者朋友应该很清楚,针对第三方DI框架的整合可以通过在定义Startup类型的ConfigureServices方法返回一个ServiceProvider来实现。但

    2024年02月09日
    浏览(53)
  • .net下优秀的IOC容器框架Autofac的使用方法,实例解析

    Autofac是一个功能强大的依赖注入容器,它提供了一种简单和灵活的方式来管理对象之间的依赖关系。下面是Autofac的一些优点: 简单易用:Autofac提供了一种直观和简洁的方式来注册和解析依赖项。它的API设计得非常易于理解和使用,使得开发人员可以轻松地配置和管理依赖关

    2024年02月05日
    浏览(55)
  • 【ASP.NET Core 基础知识】--最佳实践和进阶主题--微服务和容器化

    Tip:想要了解并学习微服务和容器化的知识,请跳转到《Docker极简教程》 一、微服务概述 1.1 什么是微服务? 微服务(Microservices)是一种软件架构风格,其中软件系统被划分为一组小型、自治的服务单元,这些服务单元围绕着业务能力进行组织,并通过轻量级的通信机制相

    2024年02月19日
    浏览(67)
  • spring6-实现简易版IOC容器

    我们都知道,Spring框架的IOC是基于Java反射机制实现的,下面我们先回顾一下java反射。 1、回顾Java反射 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包