依赖注入怎么理解_面试官的问题回答不上来怎么办

依赖注入怎么理解_面试官的问题回答不上来怎么办IOC: Inversion Of Control 控制反转DI: Dependency Injection 依赖注入1.控制反转 Invers

IOC: Inversion Of Control 控制反转

DI: Dependency Injection 依赖注入

依赖注入怎么理解_面试官的问题回答不上来怎么办

1.控制反转 Inversion Of Control 的前世今生

1.1 IOC理论产生的背景

讨论控制反转之前,先看看软件系统提出控制反转的前世今生。
一个完整精密的软件系统,组件之间就像齿轮,协同工作,相互耦合。

  • 一个零件不正常,整个系统就崩溃了。
  • 系统对象之间耦合关系无法避免,在项目规模和复杂度变大的情况下,管理类之间的依赖关系将会很复杂。
  • 对象之间耦合度很高的系统,架构师和开发人员对于系统的修改,必然会出现牵一发而动全身的情形。
  • 对象之间耦合性依赖,单元测试很复杂。

1.2 IOC理论

软件专家为此提出IOC理论,用来实现对象之间的解耦。
再来看看,控制反转(IOC)到底为什么要起这么个名字?我们来对比一下:

  1. 软件系统在没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
  2. 软件系统在引入IOC容器之后,这种情形就完全改变了,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

通过前后对比,我们不难看出:
对象A获得依赖对象B的过程,由主动变为了被动行为,控制权颠倒过来,这就是[控制反转]的由来

1.3 控制反转 和 依赖注入

有些人会把控制反转和依赖注入等同,实际上有本质区别:
控制反转是 一种思想;
依赖注入是一种设计模式。
依赖注入是实现控制反转的一种方式,但是控制反转还有其他实现方式,例如说ServiceLocator(服务定位器、依赖查找),所以不能将控制反转和依赖注入等同。

依赖注入怎么理解_面试官的问题回答不上来怎么办

2 依赖注入 Dependency Injection

依赖注入:容器全权负责组件的装配,它会把符合依赖关系的对象通过属性或者构造函数传递给需要的对象。

符合依赖倒置原:高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖于细节,细节应该依赖于抽象。

2.1 ASP.NET Core依赖注入

使用方式大体类似:
①. 定义依赖实现的接口或者抽象类
②. 在服务容器中注册组件依赖 :IServiceProvider
③. 在构造函数中注入服务, 框架会负责创建和销毁实例

依赖注入怎么理解_面试官的问题回答不上来怎么办

// 编写组件和服务public interface IMyDependency{    string WriteMessage(string message);}---public class MyDependency : IMyDependency{    public string WriteMessage(string message)    {       return #34;MyDependency.WriteMessage Message: {message}";    }}// 注册组件和依赖,下面注册的`IMyDependency`在一个web请求中有效public void ConfigureServices(IServiceCollection services){    services.AddScoped<IMyDependency, MyDependency>();    services.AddRazorPages();}---// 在构造函数注入组件public class HomeController: AbpController{    private readonly IMyDependency _dep;    public HomeController(IMyDependency dep)    {       _dep = dep;    }  public IActionResult Index()  {    var content =  _dep.WriteMessage(#34;The Reflection instance is {_dep.GetType().FullName} ");    return Content(content);  }}

在请求某个服务时,框架会完整解析出这个对象的依赖树和作用范围。

上面的示例代码形成
req—>HomeController—>IMyDependency 依赖树
IMyDependency在每个web请求范围内使用同一服务实例。

输出:MyDependency.WriteMessage Message: The Reflection instance is TestDI.MyDependency

2.2 对象生命周期

根据现实需要,前人从使用场景中总结出三种服务生命周期。
ASP.NET Core提供了一个枚举ServiceLifetime

依赖注入怎么理解_面试官的问题回答不上来怎么办

对于Scoped Service的理解:

依赖注入怎么理解_面试官的问题回答不上来怎么办

在webapp:scoped service 会在请求结束时被销毁;
在EFCore: 使用AddDbContext默认也会注册特定范围的DbContext,这意味在我们可以在一次sql连接内,使用同一个DbContext实例进行多次DB操作。

2.3 依赖注入实现原理

结合理论、使用方式 猜测依赖注入的原理:
实现DI,核心在于依赖注入容器IContainer,该容器具有以下功能
①.(容器)保存可用服务的集合
// 要用的特定对象、特定类、接口服务

②.(注册)提供一种方式将各种部件与他们依赖的服务绑定到一起;
// Add…函数或containerBuilder.Register函数,

③.(解析点)为应用程序提供一种方式来请求已配置的对象: 构造函数注入、属性注入.

运行时,框架会一层层通过反射构造实例,最终得到完整对象。

3.源码导航

利用反射产生对象是依赖注入的核心过程,这也是面试造航母时经常问到的。

.NETSystem.ReflectionSystem.Type命名空间中的类可以获取可装配组件、类、接口的信息,并提供了在运行时创建实例,调用动态实例方法、获取动态实例的能力。

当我尝试从github源码中探究[依赖注入产生对象]的伪代码时,文件/代码众多,迷路了!

依赖注入怎么理解_面试官的问题回答不上来怎么办

实际上,我们可以在依赖树的尾部对象的构造函数手动抛出异常,异常的调用栈就是一个天然的源码导航。

于是我在上面示例代码的request—-> HomeController—>MyDependency
MyDependency构造函数中添加异常代码:

    public MyDependency()
    {
       throw new Exception("exception content!");
    }

结果如下图:

依赖注入怎么理解_面试官的问题回答不上来怎么办

从Github Dependency Injection 库进入System.Reflection的调用分界线代码:

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 (var index = 0; index < parameterValues.Length; index++)
      {
         parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
       }
    }

    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;
     }
}

黄色背景行就是.NET反射特性的体现:
对类型信息(构造函数、参数)使用Invoke方法产生对象。

干货旁白

  1. 控制反转是一种在软件工程中解耦合的思想,调用方依赖接口或抽象类,减少了耦合,控制权交给了服务容器,由容器维护注册项,并将具体的实现动态注入到调用方。
  2. 有些人会把控制反转和依赖注入等同,实际上有本质区别:
    控制反转是 一种思想;
    依赖注入是一种设计模式。
    依赖注入是实现控制反转的一种方式,但是控制反转还有其他实现方式,例如说ServiceLocator,所以不能将控制反转和依赖注入等同。
  3. 在运行时,框架会解析依赖树、依赖图,通过反射在运行期生成对象。

作者:_小码甲

原文链接:https://www.cnblogs.com/JulianHuang/p/13836852

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/11851.html

(0)

相关推荐

  • 《css世界》中提到的实用技巧有哪些_环世界小技巧

    《css世界》中提到的实用技巧有哪些_环世界小技巧以下技巧的具体原理和解释请支持张老师的《CSS世界》,在这里不做展开。 一部分没录入的技巧原因是部分属性将被标准废弃,如:clip。还有一部分是因为个人觉得兼容性不好,而且CSS3的一些特性可以弥补,比如text-align:justify;,完全可以用flex布局实现。 应网…

    2023-08-13
    81
  • 比特币还能跌回一万美元吗_比特币现在还能挖到吗

    比特币还能跌回一万美元吗_比特币现在还能挖到吗

    2023-08-28
    81
  • mysql学习笔记之字段类型选择「终于解决」

    mysql学习笔记之字段类型选择「终于解决」1. 数据库的字段选择 在数据表的结构关系确定之后,这个时候就需要去确定相应的数据表的字段类型 1.1 字符串类型字段 char与varchar以及text char => char(长度) -> …

    2023-03-11
    98
  • vscode代码折叠插件_vscode好用插件

    vscode代码折叠插件_vscode好用插件这个插件还提供一个快捷键shift+command+D,一键删除本页面所有console.log,也很常用。 这样的log虽然意思很明确,但是控制台被一大堆信息铺满,自己的log被淹没在控制台各类信息当中,不是那么显眼,很难一眼定位到,这时候就想到加一点颜色等样式,显眼一点,就…

    2023-07-21
    78
  • flink 并行度和分区的关系_flink并行度

    flink 并行度和分区的关系_flink并行度Flink设置并行度的几种方式 代码中设置setParallelism() 全局设置: env.setParallelism(3); 算子设置(部分设置): sum(1).setParallelism

    2023-02-07
    106
  • Python 字典:快速检索和存储数据

    Python 字典:快速检索和存储数据Python 开发人员熟知的数据类型之一是列表,但是如果需要使用键来存储和检索元素,列表就无法满足要求了。Python 中的字典是一个非常有用的数据结构,允许您使用键来存储和检索值。在本文中,我们将深入了解 Python 字典,其用法、优缺点和使用场景。

    2024-04-03
    25
  • mysql安装8.0.23_mySQL安装教程

    mysql安装8.0.23_mySQL安装教程笔者尝试安装 MySQL 8.0.19 踩了许多小坑,然后参考了很多在线博主的博客只有部分能对笔者遇到的问题有帮助。在解决完目前安装前的所有问题后,特此记录下踩坑之处,以备将来的翻阅。 这里,笔者是…

    2023-01-30
    114
  • Oracle-RAC集群心跳

    Oracle-RAC集群心跳
    心跳线 物理布线注意事项 不建议直连网线,建议采用交换机连接方式 心跳线与业务网络分开单独接线 若公用一个交换机时,使用VLAN隔离 Oracle不支持使用…

    2023-04-05
    115

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注