[Asp.net 5] DependencyInjection项目代码分析
最近在研究开源代码,正好发现Asp.net5的源码,下载地址:https://github.com/aspnet。
今天主要讲的是DependencyInjection这部分,抛砖引玉,供大家参考,也欢迎莅临斧正。闲话不多说,下面就代码进行简单分析
项目架构如下:

一共包含DependencyInjection、DependencyInjection.Abstractions、DependencyInjection.Autofac、DependencyInjection.Ninject以及DependencyInjection.Tests五个工程。
- DependencyInjection.Abstractions 基础的接口和类,使用时对外暴露的基本信息。
- DependencyInjection 微软自己实现的DI接口
- DependencyInjection.Autofac 使用Autofac(该组件不知道是否是开源的)实现的DI
- DependencyInjection.Ninject 使用Ninject(该组件也不知道是否开源)实现的DI
- DependencyInjection.Tests 对于上面四个工程的测试代码,该部分可以不看,但是对于DI的使用还是有参考价值的。
DependencyInjection.Abstractions
该工程包含基本的接口以及一些基础的类/枚举。对于面向接口编程,使用者不需要知道实现的细节,只需要了解相应的接口便可。另外三个工程(DependencyInjection、DependencyInjection.Autofac、DependencyInjection.Ninject)就是对于该工程的相关接口的实现;使用中可以选择其中一个实现即可,也就是说使用微软这个DI,DependencyInjection.Abstractions是必须引用的类库,另外三个工程(如上所指),引入一个即可。
DependencyInjection.Abstractions 这个工程中包含的文件不是很多,下面我就将该工程文件截图:

该工程中缺少一个关键接口——IServiceProvider,该接口位于System下,有如下定义:
public interface IServiceProvider
{
object GetService(Type serviceType);
}
该接口的作用是根据传入的类型,并把它转化为相应的实例,该接口是DI的核心,是最终干活的类/接口。
但是该接口的定义存在缺陷,返回值类型是object类型的,用户使用的时候还需要进行强制类型转换,所以就对该接口进行了扩展(ServiceProviderExtensions),扩展的定义如下(省略了具体实现):
public static class ServiceProviderExtensions
{
public static T GetService<T>([NotNull] this IServiceProvider provider); public static object GetRequiredService([NotNull] this IServiceProvider provider, [NotNull] Type serviceType); public static T GetRequiredService<T>([NotNull] this IServiceProvider provider); public static IEnumerable<T> GetRequiredServices<T>([NotNull] this IServiceProvider provider); public static IEnumerable<object> GetRequiredServices([NotNull] this IServiceProvider provider, [NotNull] Type serviceType);
}
使用ServiceProvidoer创建出来的实例实际是有相应的生命周期的,框架中使用枚举ServiceLifetime表示,定义如下:
public enum ServiceLifetime
{
Singleton,//全局唯一
Scoped,//一定范围的
Transient//瞬间
}
一共分为三种,三种的时间长短是Transient<Scoped<Singleton。Transient代表仅当前实例(每次都创建一个新的),Scoped代表当前范围(会在ServiceScope中定义),Singleton代表全家唯一(类似于单例)。
IServiceScopeFactory和IServiceScope,这俩个接口很简单,故名思义IServiceScopeFactory是Scope的一个工厂类,产生一个ServiceScope对象。IServiceScope对象会生成一个IServiceProvidoer对象,一般来说通过IServiceScope就是枚举Scoped所代表的范围。这俩个接口定义如下:
public interface IServiceScopeFactory
{
IServiceScope CreateScope();
} public interface IServiceScope : IDisposable
{
IServiceProvider ServiceProvider { get; }
}
对于注册成Scoped范围的接口/类,可以通过不同的Scope拿到不同的IServiceProvidoer,之后创建不同的范围的实例,下面我将Tests工程下的一段测试代码拿出来,略作修改(将var 替换成实际的接口,阅读方便)
//services.AddScoped<IFakeScopedService, FakeService>();
public void NestedScopedServiceCanBeResolved()
{
IServiceProvider container = CreateContainer(); IServiceScopeFactory outerScopeFactory = container.GetService<IServiceScopeFactory>();
using (IServiceScope outerScope = outerScopeFactory.CreateScope())
{
IServiceScopeFactory innerScopeFactory = outerScope.ServiceProvider.GetService<IServiceScopeFactory>();
using (IServiceScope innerScope = innerScopeFactory.CreateScope())
{
IFakeScopedService outerScopedService = outerScope.ServiceProvider.GetService<IFakeScopedService>();
IFakeScopedService innerScopedService = innerScope.ServiceProvider.GetService<IFakeScopedService>(); Assert.NotEqual(outerScopedService, innerScopedService);
}
}
}
上面几个类的关系大概如下图所示:
ServiceDescriptor类:该类是一个描述类,描述DI的映射关系。该类的属性主要有3个(并不恰当),注入的源类,注入的生成类,注入的范围(ServiceLifetime)。而对于注入的生成类又分为三种:生成类的类型、生成类的实例、生成类的工厂。所以ServiceDescriptor的定义如下所示:
public class ServiceDescriptor
{
public ServiceLifetime Lifetime { get; }
public Type ServiceType { get; }
public Type ImplementationType { get; }
public object ImplementationInstance { get; }
public Func<IServiceProvider, object> ImplementationFactory { get; }
}
IServiceCollection接口比较简单就是 IList<ServiceDescriptor>。ServiceCollectionExtensions是对IServiceCollection接口的扩展方法集合。
这几个类的关系如下图所示:
剩余俩个类:ActivatorUtilities、ObjectFactory(其实是个代理/delegate)是用于反射创建实例。
整个工程我对接口、类、代理、枚举重新划分了下文件夹如下图所示:

将在下一篇文章中对DependencyInjection.Autofac、DependencyInjection.Ninject进行分析,最后再对微软自己的DI实现进行分析。
[Asp.net 5] DependencyInjection项目代码分析的更多相关文章
- [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项目代码分析2-Autofac
Microsoft.Framework.DependencyInjection.Autofac源码分析 该工程只有一个代码静态类AutofacRegistration,但是该类有3个扩展方法,以及3个 ...
- [Asp.net 5] DependencyInjection项目代码分析3-Ninject
Microsoft.Framework.DependencyInjection.Ninject 该工程内部共包含5个类文件,底层使用Ninject实现依赖注入,工程截图如下: 从文件命名可以看出,Ni ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
前面俩种实现中,很多内部细节都无法知道,微软的框架也是为了屏蔽具体实现,只让我们关注接口.但是人都是充满好奇的,依赖注入到底是怎么实现的呢? 微软又有怎样的实现呢?下面就为大家一一呈现(说实话,代码真 ...
- Jenkins+Gradle+Sonar进行Java项目代码分析
Jenkins+Maven+Sonar与Jenkins+Gradle+Sonar配置方法很相似,区别就是Java项目所用的编译工具不同,一个是maven,一个是gradle 使用maven编译工具的可 ...
随机推荐
- nw.js FrameLess Window下的窗口拖拽与窗口大小控制
nw.js FrameLess Window下的窗口拖拽与窗口大小控制 很多时候,我们觉得系统的Frame框很难看,于是想自定义. 自定义Frame的第一步是在package.config文件中将fr ...
- angular controller as syntax vs scope
今天要和大家分享的是angular从1.2版本开始带来了新语法Controller as.再次之前我们对于angular在view上的绑定都必须使用直接的scope对象,对于controller来说我 ...
- java提高篇(十四)-----字符串
可以证明,字符串操作是计算机程序设计中最常见的行为. 一.String 首先我们要明确,String并不是基本数据类型,而是一个对象,并且是不可变的对象.查看源码就会发现String类为f ...
- Qt控制台中文乱码问题
本文主要记录了Qt控制台出现中文乱码的问题,一下列出了集中编码设置的方法.以前用VC6.0写的一个贪吃蛇的游戏,今天把源文件拿出来在Qt上面运行,出现中文乱码的问题.以前也遇到过,没想到小小的乱码,折 ...
- hibernate HQL和Criteria
package com.test; import java.util.Date; import java.util.List; import org.hibernate.Query; import o ...
- ios 向工程里添加Fonts
ios 向工程里添加Fonts 1.网上搜索字体文件(后缀名为.ttf,或.odf),假如你加入的字体为微软雅黑 2.把字体库导入到工程的resouce中 3.然后在你的工程的Info.plist文件 ...
- redis常用命令、常见错误、配置技巧等分享
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/117.html?1455860236 1. redis查看当前所有的key ...
- fildder 使用方法汇总
作为网络开发人员,怎能不使用一些抓包工具呢?fildder是个不错的选择. 不过,一般情况下,我们往往使用浏览器自带的控制台的[网络]选项就可以达到查看数据的通信情况了,当然,一些浏览器不容易捕捉的事 ...
- salesforce 零基础开发入门学习(五)异步进程介绍与数据批处理Batchable
本篇知识参考:https://developer.salesforce.com/trailhead/force_com_dev_intermediate/asynchronous_apex/async ...
- 当你还在纠结于ORM的性能时,我已经远远的把你抛在脑后
最近找工作面试,问到一些过去的工作和项目经验.我把公司用到的ORM框架(LLBL Gen)拿出来谈一谈,说一下他的优势,对方却一直追问ORM的好处,性能方面的问题,让我有时候都不知道如何回答,产生了不 ...