2020年9月18日星期五

ASP.NET Core中IOC容器的实现原理

本章将和大家分享ASP.NET Core中IOC容器的实现原理。

本章将和大家分享ASP.NET Core中IOC容器的实现原理。

首先我们需要了解什么是IOC,为什么要使用IOC容器?

一、依赖

类A用到了类B,我们就说类A依赖类B。

using System;namespace MyIOCDI{ public class Test {  public void Show()  {   MyDependency myDependency = new MyDependency(); //全是细节   myDependency.Show();   Console.WriteLine($"This is {this.GetType().FullName}");  } } public class MyDependency {  public void Show()  {   Console.WriteLine($"This is {this.GetType().FullName}");  } }}

上面的示例中,类Test就依赖了MyDependency类。

二、依赖倒置原则(Dependence Inversion Principle)

依赖倒置原则:高层模块不应该依赖于低层模块,二者都应该依赖于抽象。应该依赖于抽象,而不是依赖细节。

什么是高层模块?这里的使用者Test类就称为高层模块。什么是低层模块?被使用者MyDependency类就称为低层模块。上面的示例中我们的高层模块就依赖于我们的低层模块。

那么这样子有什么不好呢?

  1、面向对象语言开发,就是类与类之间进行交互,如果高层直接依赖低层的细节,细节是多变的,那么低层的变化就导致上层的变化;

  2、如果层数多了,低层的修改会直接水波效应传递到最上层,一点细微的改动都会导致整个系统从下往上的修改。

因此,上例按照依赖倒置原则修改如下:

using System;namespace MyIOCDI{ public class Test {  public void Show()  {   IDepenency myDependency = new MyDependency(); //左边抽象右边细节   myDependency.Show();   Console.WriteLine($"This is {this.GetType().FullName}");  } } public class MyDependency : IDepenency {  public void Show()  {   Console.WriteLine($"This is {this.GetType().FullName}");  } } public interface IDepenency {  void Show(); }}

三、IOC控制反转

控制反转是一种思想,所谓“控制反转”就是反转获得依赖对象的过程。

上面示例经过改造后虽然遵循了“依赖倒置原则”,但是违背了“开放封闭原则”,因为如果有一天想要修改myDependency为YourDependency类的实例,则需要修改Test类。

因此,我们需要反转这种创建对象的过程:

using System;namespace MyIOCDI{ public class Test {  private readonly IDepenency _myDependency;  public Test(IDepenency myDependency)  {   this._myDependency = myDependency;  }  public void Show()  {   _myDependency.Show();   Console.WriteLine($"This is {this.GetType().FullName}");  } } public class MyDependency : IDepenency {  public void Show()  {   Console.WriteLine($"This is {this.GetType().FullName}");  } } public interface IDepenency {  void Show(); }}

上例中,将 _myDependency 的创建过程“反转”给了调用者。

四、依赖注入(Dependency Injection)

所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

依赖注入就是能做到构造某个对象时,将依赖的对象自动初始化并注入 。

IOC是目标是效果,需要DI依赖注入的手段。

三种注入方式:构造函数注入--属性注入--方法注入(按时间顺序)。

构造函数注入用的最多,默认找参数最多的构造函数,可以不用特性,可以去掉对容器的依赖。

五、IOC容器的实现原理

IOC容器的实现原理:

  1、启动时保存注册信息。

  2、在构造某个对象时,使用反射加特性,将依赖的对象自动初始化并注入。

  3、对对象进行生命周期管理或者进行AOP扩展等。

下面我们重点来看下模拟实现IOC容器的代码:

首先来看下项目的目录结构:

此处IOC容器中用到的自定义特性如下所示:

using System;namespace TianYaSharpCore.IOCDI.CustomAttribute{ /// <summary> /// 构造函数注入特性 /// </summary> [AttributeUsage(AttributeTargets.Constructor)] public class ConstructorInjectionAttribute : Attribute { }}
using System;namespace TianYaSharpCore.IOCDI.CustomAttribute{ /// <summary> /// 方法注入特性 /// </summary> [AttributeUsage(AttributeTargets.Method)] public class MethodInjectionAttribute : Attribute { }}
using System;namespace TianYaSharpCore.IOCDI.CustomAttribute{ /// <summary> /// 常量 /// </summary> [AttributeUsage(AttributeTargets.Parameter)] public class ParameterConstantAttribute : Attribute { }}
using System;namespace TianYaSharpCore.IOCDI.CustomAttribute{ /// <summary> /// 简称(别名) /// </summary> [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] public class ParameterShortNameAttribute : Attribute {  public string ShortName { get; private set; }  public ParameterShortNameAttribute(string shortName)  {   this.ShortName = shortName;  } }}
using System;namespace TianYaSharpCore.IOCDI.CustomAttribute{ /// <summary> /// 属性注入特性 /// </summary> [AttributeUsage(AttributeTargets.Property)] public class PropertyInjectionAttribute : Attribute { }}

IOC容器实现如下所示:

using System;namespace TianYaSharpCore.IOCDI.CustomContainer{ public class IOCContainerRegistModel {  public Type TargetType { get; set; }  /// <summary>  /// 生命周期  /// </summary>  public LifetimeType Lifetime { get; set; }  /// <summary>  /// 仅限单例  /// </summary>  public object SingletonInstance { get; set; } } /// <summary> /// 生命周期 /// </summary> public enum LifetimeType {  Transient, //瞬时  Singleton,  Scope, //作用域  PerThread //线程单例  //外部可释放单例 }}
using System;namespace TianYaSharpCore.IOCDI.CustomContainer{ /// <summary> /// IOC容器接口 /// </summary> public interface ITianYaIOCContainer {  void Register<TFrom, TTo>(string shortName = null, object[] paraList = null, LifetimeType lifetimeType = LifetimeType.Transient)   where TTo : TFrom;  TFrom Resolve<TFrom>(string shortName = null);  ITianYaIOCContainer CreateChildContainer(); }}
using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using TianYaSharpCore.IOCDI.CustomAttribute;namespace TianYaSharpCore.IOCDI.CustomContainer{ /// <summary> /// IOC容器 /// </summary> public class TianYaIOCContainer : ITianYaIOCContainer {  #region 字段或者属性  /// <summary>  /// 保存注册信息  /// </summary>  private Dictionary<string, IOCContainerRegistModel> _tianYaContainerDictionary = new Dictionary<string, IOCContainerRegistModel>();  /// <summary>  /// 保存常量的值  /// </summary>  private Dictionary<string, object[]> _tianYaContainerValueDictionary = new Dictionary<string, object[]>();  /// <summary>  /// 作用域单例的对象  /// </summary>  private Dictionary<string, object> _tianYaContainerScopeDictionary = new Dictionary<string, object>();  

没有评论:

发表评论