原文作者: Thomas Levesque 原文链接:https://thomaslevesque.com/2020/03/18/lazily-resolving-services-to-fix-circular-dependencies-in-net-core/

循环依赖的问题

在构建应用程序时,良好的设计应该应避免服务之间的循环依赖, 循环依赖是指某些组件直接或间接相互依赖,比如下面这样

如果您不小心在.NET Core应用程序使用了依赖项注入,并且引入了以下循环依赖关系,你要知道的是,项目启动会报一个循环依赖的错误,因为依赖关系周期中涉及的组件的解析将失败,比如,你具有以下组件:

•A服务,它实现了接口IA并取决于IB•B服务,它实现了接口IB并取决于IC•C服务,它实现了接口IC并取决于IA

System.InvalidOperationException: A circular dependency was detected for the service of type 'Demo.IA'.

所以应该去避免这些设计。

注入 IServiceProvider

但是,当实际应用程序达到一定程度的复杂性时,有时可能很难避免,有一天不小心给服务添加了一个依赖项,启动报错了,事情突然浮出水面, 因此,您面临一个选择:重构,来解决循环依赖的问题,理想情况下,应该去选择重构,但是实际情况中,可能项目比较紧,可能没有时间重构代码,因为要做完整的回归测试。

一种方法是将注入 IServiceProvider 到您的类中,并services.GetRequiredService()在需要使用时使用T,例如,C我前面提到的类,最初可能看起来像这样:

class C : IC
{private readonly IA _a;public C(IA a){_a = a;}public void Bar(){..._a.Foo()...}
}

为了避免依赖性循环,可以注入 IServiceProvider, 然后这样重写它:

class C : IC
{private readonly IServiceProvider _services;public C(IServiceProvider services){_services = services;}public void Bar(){...var a = _services.GetRequiredService<IA>();a.Foo();...}
}

由于在构建IA时不再需要解决问题C,因此中断了循环(至少在构建过程中),并解决了问题,但是,我不太喜欢这种方法,因为这样强制依赖了IOC,如果我使用了 Autofac 等,另一个问题是我很难看到类的依赖关系,它不明显。

巧用 Lazy<T>

下边的方法我利用了Lazy类,需要添加一个 IServiceCollection 的扩展,新建一个静态类

public static IServiceCollection AddLazyResolution(this IServiceCollection services)
{return services.AddTransient(typeof(Lazy<>),typeof(LazilyResolved<>));
}private class LazilyResolved<T> : Lazy<T>
{public LazilyResolved(IServiceProvider serviceProvider): base(serviceProvider.GetRequiredService<T>){}
}

然后再 Startup.cs 中的 ConfigureServices 方法中这样写

services.AddLazyResolution();

在依赖的类中IA,注入Lazy,当您需要使用时IA,只需访问lazy的值 Value 即可:

class C : IC
{private readonly Lazy<IA> _a;public C(Lazy<IA> a){_a = a;}public void Bar(){..._a.Value.Foo();...}
}

注意:不要访问构造函数中的值,保存Lazy即可 ,在构造函数中访问该值,这将导致我们试图解决的相同问题。

这个解决方案不是完美的,但是它解决了最初的问题却没有太多麻烦,并且依赖项仍然在构造函数中明确声明,我可以看到类之间的依赖关系。

最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102

巧用 Lazy 解决.NET Core中的循环依赖关系相关推荐

  1. java 调度etl_Easy Scheduler是一个工作流调度系统,主要解决数据研发ETL错综复杂的依赖关系...

    Easy Scheduler Easy Scheduler for Big Data 设计特点: 一个分布式易扩展的可视化DAG工作流任务调度系统.致力于解决数据处理流程中错综复杂的依赖关系,使调度系 ...

  2. 解决 .net core 中 nuget 包版本冲突问题

    解决 .net core 中 nuget 包版本冲突问题 参考文章: (1)解决 .net core 中 nuget 包版本冲突问题 (2)https://www.cnblogs.com/dudu/p ...

  3. 你的眼睛背叛你的心:解决 .NET Core 中 GetHostAddressesAsync 引起的 EnyimMemcached 死锁问题

    你的眼睛背叛你的心:解决 .NET Core 中 GetHostAddressesAsync 引起的 EnyimMemcached 死锁问题 参考文章: (1)你的眼睛背叛你的心:解决 .NET Co ...

  4. spring自动装配依赖包_解决Spring自动装配中的循环依赖

    spring自动装配依赖包 我认为这篇文章是在企业应用程序开发中使用Spring的最佳实践. 使用Spring编写企业Web应用程序时,服务层中的服务量可能会增加. 服务层中的每个服务可能会消耗其他服 ...

  5. 解决Spring自动装配中的循环依赖

    我认为这篇文章是在企业应用程序开发中使用Spring的最佳实践. 使用Spring编写企业Web应用程序时,服务层中的服务量可能会增加. 服务层中的每个服务可能会消耗其他服务,这些服务将通过@Auto ...

  6. Spring中的循环依赖解决详解

    目录 1 什么是循环依赖? 1.1 构造器循环依赖 1.2 field属性注入循环依赖 1.3 field属性注入循环依赖(prototype) 2 循环依赖处理 2.1 构造器循环依赖(无法解决) ...

  7. 面试:讲一讲Spring中的循环依赖

    前言 Spring中的循环依赖一直是Spring中一个很重要的话题,一方面是因为源码中为了解决循环依赖做了很多处理,另外一方面是因为面试的时候,如果问到Spring中比较高阶的问题,那么循环依赖必定逃 ...

  8. 面试必杀技,讲一讲Spring中的循环依赖

    本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...

  9. Spring中的循环依赖

    目录 一.什么是循环依赖? 二.Bean的生命周期 2.1 Spring Bean 的生命周期 2.2 Bean 的生成步骤 三.三级缓存 3.1三个缓存分别有什么作用 四.思路分析 4.1 为什么 ...

最新文章

  1. ATSS : 目标检测的自适应正负anchor选择,很扎实的trick | CVPR 2020
  2. C++源代码免杀之函数的动态调用
  3. ASP.NET MVC Filter过滤机制(过滤器、拦截器)
  4. java给文件添加水印_Java在PDF中添加水印(文本/图片水印)
  5. Windows中使用包管理器(类似于apt/yum的) - Chocolatey
  6. 关于Revit API修改元素参数的问题?
  7. win10系统开启扫描仪服务器,win10通用扫描仪安装步骤
  8. 斯坦福大学公开课:量子力学
  9. 裸金属服务器启动之PXE与IPXE实践
  10. 人脸、微笑、口罩识别
  11. vb语言中怎样编码窗体中所有字体加粗_VBText控件中使字体加粗和倾斜的代码是什么...
  12. dlink 备份文件_D-Link路由器备份路由器配置信息教程
  13. 某程序员在网吧敲代码,出类拔萃,网友:为何我被打的却是我
  14. 残疾人竞赛计算机程序,第五届全国残疾人职业技能竞赛竞赛标准计算机程序.doc...
  15. html word-break,HTML Style wordBreak用法及代码示例
  16. 机场内部人员都是这么定的机票的!
  17. CV GaussianBlur
  18. 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
  19. 委托构造函数继承构造函数
  20. BP算法总结+从输入-隐层-输出的逐步手推

热门文章

  1. .NET中RabbitMQ的使用
  2. LINUX BASH SHELL,小小学习一下
  3. 心得9--jsp设计模版
  4. 一份详尽的利用 Kubeadm部署 Kubernetes 1.13.1 集群指北
  5. js中关于Blob对象的介绍与使用
  6. 《版式设计——日本平面设计师参考手册》—第1章应用对象样式
  7. Xamarin.Android和UWP之MVVM的简单使用(二)
  8. 个人项目耗时对比记录表
  9. common Lisp学习笔记(十二)
  10. jQuery实现等比例缩放大图片让大图片自适应页面布局