本章将和大家分享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>();
没有评论:
发表评论