[Asp.net 5] DependencyInjection项目代码分析3-Ninject
Microsoft.Framework.DependencyInjection.Ninject
该工程内部共包含5个类文件,底层使用Ninject实现依赖注入,工程截图如下:
从文件命名可以看出,NinjectServiceProvider和NinjectServiceScopeFactory分别是接口IServiceProvider和IServiceScopeFactory的实现类。
(IServiceScope接口的实现类作为NinjectServiceScopeFactory内部类而存在,没有作为单独的文件。)
而工程的入口依旧是Registration为结尾的NinjectRegistration类。
NinjectRegistration
文件代码如下
public static class NinjectRegistration { public static void Populate(this IKernel kernel, IEnumerable<ServiceDescriptor> descriptors) { kernel.Load(new ServiceProviderNinjectModule(descriptors)); } public static IBindingNamedWithOrOnSyntax<T> InRequestScope<T>( this IBindingWhenInNamedWithOrOnSyntax<T> binding) { return binding.InScope(context => context.Parameters.GetScopeParameter()); } internal static ScopeParameter GetScopeParameter(this IEnumerable<IParameter> parameters) { return (ScopeParameter)(parameters .Where(p => p.Name == typeof(ScopeParameter).FullName) .SingleOrDefault()); } internal static IEnumerable<IParameter> AddOrReplaceScopeParameter( this IEnumerable<IParameter> parameters, ScopeParameter scopeParameter) { return parameters .Where(p => p.Name != typeof(ScopeParameter).FullName) .Concat(new[] { scopeParameter }); } }
静态方法:
Populate:作用是将ServiceProviderNinjectModule注册到内核中。对于Ninject大多数时候都会将自定义继承自NinjectModule的类注册到内核中,并且使用该继承类管理依赖注入。
GetScopeParameter:获取所有“ScopeParameter”类型的参数
AddOrReplaceScopeParameter:获取所有“ScopeParameter”参数,并且将它替换成传入的“scopeParameter”。
InRequestScope:在“binding.InScope”中添加“ScopeParameter”。
总体说来,该文件都是些辅助方法,也是对外初始化的接口。
ServiceProviderNinjectModule
文件代码如下:
internal class ServiceProviderNinjectModule : NinjectModule { private readonly IEnumerable<ServiceDescriptor> _serviceDescriptors; public ServiceProviderNinjectModule( IEnumerable<ServiceDescriptor> serviceDescriptors) { _serviceDescriptors = serviceDescriptors; } public override void Load() { foreach (var descriptor in _serviceDescriptors) { IBindingWhenInNamedWithOrOnSyntax<object> binding; if (descriptor.ImplementationType != null) { binding = Bind(descriptor.ServiceType).To(descriptor.ImplementationType); } else if (descriptor.ImplementationFactory != null) { binding = Bind(descriptor.ServiceType).ToMethod(context => { var serviceProvider = context.Kernel.Get<IServiceProvider>(); return descriptor.ImplementationFactory(serviceProvider); }); } else { binding = Bind(descriptor.ServiceType).ToConstant(descriptor.ImplementationInstance); } switch (descriptor.Lifetime) { case ServiceLifetime.Singleton: binding.InSingletonScope(); break; case ServiceLifetime.Scoped: binding.InRequestScope(); break; case ServiceLifetime.Transient: binding.InTransientScope(); break; } } Bind<IServiceProvider>().ToMethod(context => { var resolver = context.Kernel.Get<IResolutionRoot>(); var inheritedParams = context.Parameters.Where(p => p.ShouldInherit); var scopeParam = new ScopeParameter(); inheritedParams = inheritedParams.AddOrReplaceScopeParameter(scopeParam); return new NinjectServiceProvider(resolver, inheritedParams.ToArray()); }).InRequestScope(); Bind<IServiceScopeFactory>().ToMethod(context => { return new NinjectServiceScopeFactory(context); }).InRequestScope(); } }
虽然代码量相对多一些,不过内部逻辑也很简单。
首先是按照惯例,将表示依赖注入关系的IEnumerable<ServiceDescriptor>类型参数传入。
之后重载Load方法,在内核调用时根据IEnumerable<ServiceDescriptor>初始化依赖注入关系。
Load方法,首先遍历IEnumerable<ServiceDescriptor> 对于每一个ServiceDescriptor对象,按照实现类类型、实现类工厂、实现类实例的顺序注入,之后设置相应的生命周期。最后注入IServiceProvider为NinjectServiceProvider、IServiceScopeFactory为NinjectServiceScopeFactory类型。
*需要注意的是NinjectServiceProvider和NinjectServiceScopeFactory注入的范围是Scope,并且对于每个NinjectServiceProvider都会替换其scopeParam参数,以保证其Scope范围。
NinjectServiceProvider
internal class NinjectServiceProvider : IServiceProvider { private static readonly MethodInfo _getAll; private readonly IResolutionRoot _resolver; private readonly IParameter[] _inheritedParameters; private readonly object[] _getAllParameters; static NinjectServiceProvider() { _getAll = typeof(ResolutionExtensions).GetMethod( "GetAll", new Type[] { typeof(IResolutionRoot), typeof(IParameter[]) }); } public NinjectServiceProvider(IResolutionRoot resolver, IParameter[] inheritedParameters) { _resolver = resolver; _inheritedParameters = inheritedParameters; _getAllParameters = new object[] { resolver, inheritedParameters }; } public object GetService(Type type) { return GetSingleService(type) ?? GetLast(GetAll(type)) ?? GetMultiService(type); } private object GetSingleService(Type type); private IEnumerable GetMultiService(Type collectionType); private IEnumerable GetAll(Type type); private static object GetLast(IEnumerable services); }
该类首先静态构造函数在类文件加载时,进行初始化,将范性扩展方法“IEnumerable<T> GetAll<T>(this IResolutionRoot root, params IParameter[] parameters)” 赋值给内部变量“_getAll”。之后类构造函数初始化,该构造函数将IResolutionRoot _resolver赋值(依赖注入的内部的核心控制类),IParameter[] _inheritedParameters赋值,并且为“_getAll”的参数初始化_getAllParameters。
当系统获取实现类实例时,系统调用GetService(Type)方法。
- 系统首先调用GetSingleService[内部为_resolver.TryGet(type, _inheritedParameters)],获取简单类型的实现。
- 如果简单类型为空,则获取将泛型类型的数据。将GetAll方法的T类型换成实际的类型,之后获取所有该类型的实例,最后去所有实例中最后一个。
private IEnumerable GetAll(Type type) { var getAll = _getAll.MakeGenericMethod(type); return (IEnumerable)getAll.Invoke(null, _getAllParameters); }
- 如果获取所有该类型实例仍然为空,则该Type类型可能为IEnumerable<T>类型,则获取T类型,调用GetAll方法。
NinjectServiceScopeFactory和NinjectServiceScope
这里俩个类继承自IServiceScopeFactory和IServiceScope。
NinjectServiceScopeFactory仅仅在内部创建了NinjectServiceScope对象,代码如下:
public NinjectServiceScopeFactory(IContext context) { _resolver = context.Kernel.Get<IResolutionRoot>(); _inheritedParameters = context.Parameters.Where(p => p.ShouldInherit); } public IServiceScope CreateScope() { return new NinjectServiceScope(_resolver, _inheritedParameters); }
而在NinjectServiceScope内部,每次都是使用新的ScopeParameter参数构建NinjectServiceProvider实例,以确保每次都开启一个新的Scope。代码如下:
public NinjectServiceScope( IResolutionRoot resolver, IEnumerable<IParameter> inheritedParameters) { _scope = new ScopeParameter(); inheritedParameters = inheritedParameters.AddOrReplaceScopeParameter(_scope); _serviceProvider = new NinjectServiceProvider(resolver, inheritedParameters.ToArray()); }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。