[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
前面俩种实现中,很多内部细节都无法知道,微软的框架也是为了屏蔽具体实现,只让我们关注接口。但是人都是充满好奇的,依赖注入到底是怎么实现的呢?
微软又有怎样的实现呢?下面就为大家一一呈现(说实话,代码真不好读)
先看下核心类:ServiceTable
internal class ServiceTable { private readonly object _sync = new object(); private readonly Dictionary<Type, ServiceEntry> _services; private readonly Dictionary<Type, List<IGenericService>> _genericServices; private readonly ConcurrentDictionary<Type, Func<ServiceProvider, object>> _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>(); public ServiceTable(IEnumerable<ServiceDescriptor> descriptors) { _services = new Dictionary<Type, ServiceEntry>(); _genericServices = new Dictionary<Type, List<IGenericService>>(); foreach (var descriptor in descriptors) { var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo(); if (serviceTypeInfo.IsGenericTypeDefinition) { Add(descriptor.ServiceType, new GenericService(descriptor)); } else if (descriptor.ImplementationInstance != null) { Add(descriptor.ServiceType, new InstanceService(descriptor)); } else if (descriptor.ImplementationFactory != null) { Add(descriptor.ServiceType, new FactoryService(descriptor)); } else { Add(descriptor.ServiceType, new Service(descriptor)); } } } public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices { get { return _realizedServices; } } public bool TryGetEntry(Type serviceType, out ServiceEntry entry) { lock (_sync) { if (_services.TryGetValue(serviceType, out entry)) { return true; } else if (serviceType.GetTypeInfo().IsGenericType) { var openServiceType = serviceType.GetGenericTypeDefinition(); List<IGenericService> genericEntry; if (_genericServices.TryGetValue(openServiceType, out genericEntry)) { foreach (var genericService in genericEntry) { var closedService = genericService.GetService(serviceType); if (closedService != null) { Add(serviceType, closedService); } } return _services.TryGetValue(serviceType, out entry); } } } return false; } public void Add(Type serviceType, IService service) { lock (_sync) { ServiceEntry entry; if (_services.TryGetValue(serviceType, out entry)) { entry.Add(service); } else { _services[serviceType] = new ServiceEntry(service); } } } public void Add(Type serviceType, IGenericService genericService) { lock (_sync) { List<IGenericService> genericEntry; if (!_genericServices.TryGetValue(serviceType, out genericEntry)) { genericEntry = new List<IGenericService>(); _genericServices[serviceType] = genericEntry; } genericEntry.Add(genericService); } } }
首先看代码的属性:
private readonly Dictionary<Type, ServiceEntry> _services; private readonly Dictionary<Type, List<IGenericService>> _genericServices; private readonly ConcurrentDictionary<Type, Func<ServiceProvider, object>> _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();
ServiceEntry类等后面介绍,可以把它当作能够产生一个object对象的类。所以“_services”是存放类型和实例对应关系的字典。
“_genericServices”顾名思义,肯定和泛型有关系,实际上“_genericServices”的Type是类似于“List<T>”这种包含泛型定义的类型。
最后一个_realizedServices定义比较复杂。可能看不明白是什么意思。实际也是定义了一个字典表(ConcurrentDictionary),与Dictionary不同的是,对多线程支持较好。字典表的第一个泛型实参是Type,第二参数是一个Func代理;而这个Func代理(可以百度C#+Func查询详细的用法)的入参是ServiceProvider,返回值是object.
[在注入获取实例时,会查询_realizedServices是否已经包含该实例,如果有则查询,如果没有则到_services中生产一个,之后将生成的结果加到realizedServices中,并且返回;但是如果_services也没有呢,则将_genericServices中泛型进行类型“实参话”,将所有类型匹配的都加入到_services中,之后从_services中获取]
从类的构造函数中可以发现,根据ServiceDescriptor对象构建IService(IGenericService)顺序是:GenericService->InstanceService->FactoryService->Service(和Autofac、Ninject是不同的)。
接口定义:IGenericService、IService、IServiceCallSite
internal interface IGenericService { ServiceLifetime Lifetime { get; } IService GetService(Type closedServiceType); }
internal interface IService { IService Next { get; set; } ServiceLifetime Lifetime { get; } IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain); }
internal interface IServiceCallSite { object Invoke(ServiceProvider provider); Expression Build(Expression provider); }
IServiceCallSite接口:类似一个工厂类,能够通过Invoke调用生成object对象,也就是依赖注入最后产生的对象都是由该接口的实例负责。
IService接口:Lifetime生命周期,CreateCallSite通过ServiceProvider创建IServiceCallSite,也就是能够间接创建实例对象。我觉得Next属性放到接口里不算太恰当,Next对象引用自己,使得IService具有链性结构。
IGenericService接口:产生一个IService接口。
[此处有一个可以思考的问题,IGenericService和IService设计成俩个接口是容易理解的,泛型和非泛型差距很大,可以不共用一个接口。但是IService接口和IServiceCallSite接口为什么不可以合并成一个接口?接口定义如下所示:
internal interface IService { ServiceLifetime Lifetime { get; } object Invoke(ServiceProvider provider); }
]
ServiceEntry类
internal class ServiceEntry { private object _sync = new object(); public ServiceEntry(IService service) { First = service; Last = service; } public IService First { get; private set; } public IService Last { get; private set; } public void Add(IService service) { lock (_sync) { Last.Next = service; Last = service; } } }
ServiceEntry类相对比较简单。相当于一个IService的单向链表,之后包含了链表的起始节点,以及结束节点。Add方法能够让新节点添加到链表的尾部。
[百思不得其解,为啥不使用LinkList这种列表结构,或者自己写个泛型类的列表,在IService内添加自引用,总觉得不是一种良好的设计]
回头我们看下ServiceTable的Dictionary<Type, ServiceEntry> _services属性,实际上是对某个类型,注册了很多个IService接口,并且这些接口是按照列表顺序存放的。
回头看看ServiceTable
俩个Add方法很简单,判断该Type类型的列表/数组是否存在,如果存在,调用列表/数组的添加方法,不存在则创建一个。
比较有意思的是TryGet方法,先在非泛型下搜索,如果不存在,则到泛型下搜索。并且将泛型“实参化”。这段代码值得我们深入研究。
public bool TryGetEntry(Type serviceType, out ServiceEntry entry) { lock (_sync) { if (_services.TryGetValue(serviceType, out entry)) { return true; } else if (serviceType.GetTypeInfo().IsGenericType) { var openServiceType = serviceType.GetGenericTypeDefinition(); List<IGenericService> genericEntry; if (_genericServices.TryGetValue(openServiceType, out genericEntry)) { foreach (var genericService in genericEntry) { var closedService = genericService.GetService(serviceType); if (closedService != null) { Add(serviceType, closedService); } } return _services.TryGetValue(serviceType, out entry); } } } return false; }
[ServiceTable的俩个属性Dictionary<Type, ServiceEntry> _services和Dictionary<Type, List<IGenericService>> _genericServices这俩个属性中一个使用单向列表,一个使用list,有洁癖的朋友会感觉很不爽有没有,有没有。为啥不能统一了让我们舒舒服服的呢]