[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());
}
[Asp.net 5] DependencyInjection项目代码分析3-Ninject的更多相关文章
- [Asp.net 5] DependencyInjection项目代码分析-目录
微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)
Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)
这个系列已经写了5篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)
这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)
在 DependencyInjection项目代码分析4-微软的实现(1)中介绍了“ServiceTable”.“ServiceEntry”.“IGenericService”.“IService”. ...
- [Asp.net 5] DependencyInjection项目代码分析
最近在研究开源代码,正好发现Asp.net5的源码,下载地址:https://github.com/aspnet. 今天主要讲的是DependencyInjection这部分,抛砖引玉,供大家参考,也 ...
- [Asp.net 5] DependencyInjection项目代码分析2-Autofac
Microsoft.Framework.DependencyInjection.Autofac源码分析 该工程只有一个代码静态类AutofacRegistration,但是该类有3个扩展方法,以及3个 ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
前面俩种实现中,很多内部细节都无法知道,微软的框架也是为了屏蔽具体实现,只让我们关注接口.但是人都是充满好奇的,依赖注入到底是怎么实现的呢? 微软又有怎样的实现呢?下面就为大家一一呈现(说实话,代码真 ...
- Jenkins+Gradle+Sonar进行Java项目代码分析
Jenkins+Maven+Sonar与Jenkins+Gradle+Sonar配置方法很相似,区别就是Java项目所用的编译工具不同,一个是maven,一个是gradle 使用maven编译工具的可 ...
随机推荐
- 在WebApi中基于Owin OAuth使用授权发放Token
如何基于Microsoft.Owin.Security.OAuth,使用Client Credentials Grant授权方式给客户端发放access token? Client Credentia ...
- angularjs移除不必要的$watch
在我们的web page,特别是移动设备上,太多的angular $watch将可能导致性能问题.这篇文章将解释如何去移除额外的$watch提高你的应用程序性能. $watch如果不再使用,我们最好将 ...
- java提高篇(四)-----理解java的三大特性之多态
面向对象编程有三大特性:封装.继承.多态. 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法. 继承 ...
- 关于基本类型值和引用类型值以及Vue官方API的array.$remove(reference)
今天又是孟哥解惑. 数组里的元素也是指向内存地址么? 这个要分情况的. 无论a[0],a[2]在什么地方,只要其值是基本类型值,就是值的比较,只要其值是引用类型(对象),就是内存地址的比较. Vue官 ...
- 说说设计模式~ 模版模式(Template)
返回目录 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...
- [数据库连接池二]Java数据库连接池--C3P0和JDNI.
前言:上一篇文章中讲了DBCP的用法以及实现原理, 这一篇再来说下C3P0和JDNI的用法. 1.1.C3P0数据源 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规 ...
- Atitit 代理与分销系统(1) 子代理 充值总额功能设计概览 sum() groubpy subagt
Atitit 代理与分销系统(1) 子代理 充值总额功能设计概览 sum() groubpy subagt Keyword 分组与聚合操作. 一个for做分组...里面的做聚合... 数据g操作查 ...
- Atitit cnchar simp best list 汉字简化方案 最简化汉字256个
Atitit cnchar simp best list 汉字简化方案 最简化汉字256个 1.1. 最简化发音1 1.2. 根据笔画密度,删除了密度高的字..1 1.3. 使用同发音的英文字母等代 ...
- C#并行编程-PLINQ:声明式数据并行
目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-PLINQ:声明式数据并行 背景 通过LINQ可 ...
- Redis 监控
redis 监控有 redis-live 和 redis-stat Redis-Live是一个用来监控redis实例,分析查询语句并且有web界面的监控工具,使用python编写. redis-sta ...