您的位置:首页 > 编程语言 > ASP

ASP.Net Core-依赖注入IoC

2016-07-15 16:48 2076 查看
一、Ioc

IoC全称Inverse of Control,控制反转。

类库和框架的不同之处在于,类库是实现某种单一功能的API,框架是针对一个任务把这些单一功能串联起来形成一个完整的流程,这个流程在一个引擎驱动下被执行。

IoC的总体设计是要把在应用程序的流程控制转移到框架中,实现对流程的复用,这 符合软件设计的基本原则-重用性。

IoC不是一种设计模式,它是一种设计原则。并且很多设计模式都遵循了这种原则。比如:模板模式、工厂模式、抽象工厂模式。

二、DI

DI全称Dependency Indection,依赖注入。它是IoC模式的一种。

我们写的对象要完成某个功能可能要依赖于另外一个对象,比如我们要添加一个人员,往往会在逻辑层调用数据操作层来实现添加到数据库的操作。DI会在程序初始化的时候,把数据操作层的接口和实现接口的类关联起来,那么在逻辑层我们只要声明要调用的具体数据操作层的接口,调用接口的方法,这样就实现了逻辑层和数据操作层的解耦。

所谓依赖注入可以理解为一种针对依赖的字段或者属性的一种自动初始化方式。

举例说明,当我们通过VS2015创建了一个.Net Core项目,并且带有个人身份验证Identity,具体如何创建在此不再细说。

我们看到在Startup中,有个方法

1:   internal class ServiceProvider : IServiceProvider, IDisposable

2: {

3:     public ServiceProvider Root { get; private set; }

4:     public ServiceTable ServiceTable { get; private set; }

5:     public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices { get; private set; } = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();

6:     public IList<IDisposable> TransientDisposableServices { get; private set; } = new List<IDisposable>();

7:     public ConcurrentDictionary<IService, object> ResolvedServices { get; private set; } = new ConcurrentDictionary<IService, object>();

8:

9:     public ServiceProvider(IServiceCollection services)

10:     {

11:         this.Root         = this;

12:         this.ServiceTable     = new ServiceTable(services);

13:     }

14:

15:     public object GetService(Type serviceType)

16:     {

17:         Func<ServiceProvider, object> serviceAccessor;

18:         if (this.RealizedServices.TryGetValue(serviceType, out serviceAccessor))

19:         {

20:             return serviceAccessor(this);

21:         }

22:

23:         IServiceCallSite serviceCallSite = this.GetServiceCallSite(serviceType, new HashSet<Type>());

24:         if (null != serviceCallSite)

25:         {

26:             var providerExpression = Expression.Parameter(typeof(ServiceProvider), "provider");

27:             this.RealizedServices[serviceType] = Expression.Lambda<Func<ServiceProvider, object>>(serviceCallSite.Build(providerExpression), providerExpression).Compile();

28:             return serviceCallSite.Invoke(this);

29:         }

30:

31:         this.RealizedServices[serviceType] = _ => null;

32:         return null;

33:     }

34:

35:     public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)

36:     {

37:             try

38:             {

39:                 if (callSiteChain.Contains(serviceType))

40:                 {

41:                     throw new InvalidOperationException(string.Format("A circular dependency was detected for the service of type '{0}'", serviceType.FullName);

42:                 }

43:                 callSiteChain.Add(serviceType);

44:

45:                 ServiceEntry serviceEntry;

46:                 if (this.ServiceTable.ServieEntries.TryGetValue(serviceType,

47:                     out serviceEntry))

48:                 {

49:                     return serviceEntry.Last.CreateCallSite(this, callSiteChain);

50:                 }

51:

52:                 //省略其他代码

53:

54:                 return null;

55:             }

56:             finally

57:             {

58:                 callSiteChain.Remove(serviceType);

59:             }

60:     }

61:

62:     public void Dispose()

63:     {

64:         Array.ForEach(this.TransientDisposableServices.ToArray(), _ => _.Dispose());

65:         Array.ForEach(this.ResolvedServices.Values.ToArray(), _ => (_ as IDisposable)?.Dispose());

66:         this.TransientDisposableServices.Clear();

67:         this.ResolvedServices.Clear();

68:     }

69:     //其他成员

70: }


View Code

以上借助他人的代码片段,ServiceProvider中主要有几个属性,root指向自己;RealizedServices 就是在我们讲解ServiceCallSite时说道,最后得到的Service会被生成委托以便下次调用,这个委托就存在这个属性中。

这个类最主要的方法就是GetService,主要逻辑就是从RealizedServices 获取当前服务的实例,如果有,直接返回,如果没有,会从ServiceTable中找到对应的ServiceEntry,如果没有返回null,如果有,调用ServiceEntry所在列表最后一个Service的CreateServiceCallSite方法创建一个ServiceCallSite对象(这一点说明了如果针对同一个服务类型注册了多个ServiceDescriptor,在提供单个服务的时候总是使用最后一个 ServiceDescriptor)。

综上,.net core中的DI容器的主要对象就是ServiceProvider、ServiceCallSite、Service、ServiceEntry和ServiceTable。主要的流程控制都放在ServiceProvider类中,这个类有一个ServiceTable(就是ServiceType和ServiceEntry的对应列表)。ServiceEntry就是一个链表,链接了当前ServiceType的所有的实例(不过得到的实例总是以最后一个为准),实例的类型都是Service类型。Service主要就是获取ServiceCallSite对象,这个对象就是封装了所有的获取具体服务实例的逻辑,主要通过Invoke得到实例,再调用Build生成表达式委托,存在ServiceProvider中。

ServiceProvider主要有一个方法GetService获取服务实例。主要逻辑就是从RealizedServices 获取当前服务的实例,如果有,直接返回,如果没有,会从ServiceTable中找到对应的ServiceEntry,如果没有返回null,如果有,调用ServiceEntry所在列表最后一个Service的CreateServiceCallSite方法创建一个ServiceCallSite对象(这一点说明了如果针对同一个服务类型注册了多个ServiceDescriptor,在提供单个服务的时候总是使用最后一个 ServiceDescriptor)。

过后思考:

1. ServiceCallSite:获取我们要的最终的服务实例并缓存起来以备下次调用。

2.Service:获取ServiceCallSite,由我们注册的服务转换而来,链表形式存在,整个链表表示相同实例类型的实例。

3.ServiceEntry:对链表Service的封装,有First、Last表示链表的第一个和最后一个,还有个Add方法。

4.ServiceTable:主要对象就是Dictionary<Type,ServiceEntry> _service,表示服务类型和服务实例链表的对应关系。

5.ServiceProvider:整个DI功能的控制者,主要方法就是GetService,根据类型获取实例。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: