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());
}
*AddOrReplaceScopeParameter当ScopeParameter类型参数存在时,将其替换成_scope,不存在时添加。

[Asp.net 5] DependencyInjection项目代码分析3-Ninject的更多相关文章

  1. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  2. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...

  3. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)

    这个系列已经写了5篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...

  4. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)

    这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...

  5. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)

    在 DependencyInjection项目代码分析4-微软的实现(1)中介绍了“ServiceTable”.“ServiceEntry”.“IGenericService”.“IService”. ...

  6. [Asp.net 5] DependencyInjection项目代码分析

    最近在研究开源代码,正好发现Asp.net5的源码,下载地址:https://github.com/aspnet. 今天主要讲的是DependencyInjection这部分,抛砖引玉,供大家参考,也 ...

  7. [Asp.net 5] DependencyInjection项目代码分析2-Autofac

    Microsoft.Framework.DependencyInjection.Autofac源码分析 该工程只有一个代码静态类AutofacRegistration,但是该类有3个扩展方法,以及3个 ...

  8. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)

    前面俩种实现中,很多内部细节都无法知道,微软的框架也是为了屏蔽具体实现,只让我们关注接口.但是人都是充满好奇的,依赖注入到底是怎么实现的呢? 微软又有怎样的实现呢?下面就为大家一一呈现(说实话,代码真 ...

  9. Jenkins+Gradle+Sonar进行Java项目代码分析

    Jenkins+Maven+Sonar与Jenkins+Gradle+Sonar配置方法很相似,区别就是Java项目所用的编译工具不同,一个是maven,一个是gradle 使用maven编译工具的可 ...

随机推荐

  1. 在WebApi中基于Owin OAuth使用授权发放Token

    如何基于Microsoft.Owin.Security.OAuth,使用Client Credentials Grant授权方式给客户端发放access token? Client Credentia ...

  2. angularjs移除不必要的$watch

    在我们的web page,特别是移动设备上,太多的angular $watch将可能导致性能问题.这篇文章将解释如何去移除额外的$watch提高你的应用程序性能. $watch如果不再使用,我们最好将 ...

  3. java提高篇(四)-----理解java的三大特性之多态

    面向对象编程有三大特性:封装.继承.多态. 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法. 继承 ...

  4. 关于基本类型值和引用类型值以及Vue官方API的array.$remove(reference)

    今天又是孟哥解惑. 数组里的元素也是指向内存地址么? 这个要分情况的. 无论a[0],a[2]在什么地方,只要其值是基本类型值,就是值的比较,只要其值是引用类型(对象),就是内存地址的比较. Vue官 ...

  5. 说说设计模式~ 模版模式(Template)

    返回目录 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...

  6. [数据库连接池二]Java数据库连接池--C3P0和JDNI.

    前言:上一篇文章中讲了DBCP的用法以及实现原理, 这一篇再来说下C3P0和JDNI的用法. 1.1.C3P0数据源 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规 ...

  7. Atitit  代理与分销系统(1)  子代理 充值总额功能设计概览 sum() groubpy subagt

    Atitit  代理与分销系统(1)  子代理 充值总额功能设计概览 sum() groubpy subagt Keyword 分组与聚合操作. 一个for做分组...里面的做聚合... 数据g操作查 ...

  8. Atitit cnchar simp best list  汉字简化方案 最简化汉字256个

    Atitit cnchar simp best list  汉字简化方案 最简化汉字256个 1.1. 最简化发音1 1.2. 根据笔画密度,删除了密度高的字..1 1.3. 使用同发音的英文字母等代 ...

  9. C#并行编程-PLINQ:声明式数据并行

    目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-PLINQ:声明式数据并行 背景 通过LINQ可 ...

  10. Redis 监控

    redis 监控有 redis-live 和 redis-stat Redis-Live是一个用来监控redis实例,分析查询语句并且有web界面的监控工具,使用python编写. redis-sta ...