zoukankan      html  css  js  c++  java
  • [Asp.net 5] DependencyInjection项目代码分析3-Ninject

    Microsoft.Framework.DependencyInjection.Ninject

    该工程内部共包含5个类文件,底层使用Ninject实现依赖注入,工程截图如下:

    从文件命名可以看出,NinjectServiceProviderNinjectServiceScopeFactory分别是接口IServiceProviderIServiceScopeFactory的实现类。

    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();
            }
        }
    View Code

     虽然代码量相对多一些,不过内部逻辑也很简单。

    首先是按照惯例,将表示依赖注入关系的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,不存在时添加。
  • 相关阅读:
    CRL线程池调度和配置的一些细节
    迁移到iis7
    musicstore edit方法出错的原因和解决方法
    如何分离出EF的三份结构定义文件
    在GridView中 鼠标移动到行 该行颜色变换
    飘逸程序员的老家
    [转贴]ASP.NET中常用的26个优化性能方案
    【转贴】在ASP.NET中显示进度条ASP.NET
    在使用GridView中删除的按钮弹出提示框最简单的一中方法
    【转贴】ASP.NET图表控件
  • 原文地址:https://www.cnblogs.com/watermoon2/p/4513739.html
Copyright © 2011-2022 走看看