[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)
这个系列已经写了6篇,链接地址如下:
如果想对本篇有个更好的了解,建议需要先看
“[Asp.net 5] DependencyInjection项目代码分析”
“[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)”
“[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)”。
"[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)"
继续ServiceProvider类
在之前的讲解中我们提到过Service类调用CreateCallSite方法时会递归调用,但是我们没具体说明如何递归调的。实际上Service类,通过反射创建实例的时候,会实例化的参数对象,而实例话参数对象通过ServiceProvider类创建,而ServiceProvider类创建参数的实例,又需要通过Service类(如果是通过Type注册的)创建。下面我们把Service的CreateInstanceCallSite方法以及ServiceProvider相关的方法列出来。
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
{
ConstructorInfo[] constructors = _descriptor.ImplementationType.GetTypeInfo()
.DeclaredConstructors
.Where(IsInjectable)
.ToArray(); // TODO: actual service-fulfillment constructor selection
if (constructors.Length == )
{
ParameterInfo[] parameters = constructors[].GetParameters();
IServiceCallSite[] parameterCallSites = new IServiceCallSite[parameters.Length];
for (var index = ; index != parameters.Length; ++index)
{
parameterCallSites[index] = provider.GetServiceCallSite(parameters[index].ParameterType, callSiteChain); if (parameterCallSites[index] == null && parameters[index].HasDefaultValue)
{
parameterCallSites[index] = new ConstantCallSite(parameters[index].DefaultValue);
}
if (parameterCallSites[index] == null)
{
throw new InvalidOperationException(Resources.FormatCannotResolveService(
parameters[index].ParameterType,
_descriptor.ImplementationType));
}
}
return new ConstructorCallSite(constructors[], parameterCallSites);
} return new CreateInstanceCallSite(_descriptor);
}
Service的CreateCallSite
internal IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)
{
try
{
if (callSiteChain.Contains(serviceType))
{
throw new InvalidOperationException(Resources.FormatCircularDependencyException(serviceType));
} callSiteChain.Add(serviceType); ServiceEntry entry;
if (_table.TryGetEntry(serviceType, out entry))
{
return GetResolveCallSite(entry.Last, callSiteChain);
} object emptyIEnumerableOrNull = GetEmptyIEnumerableOrNull(serviceType);
if (emptyIEnumerableOrNull != null)
{
return new EmptyIEnumerableCallSite(serviceType, emptyIEnumerableOrNull);
} return null;
}
finally
{
callSiteChain.Remove(serviceType);
} } internal IServiceCallSite GetResolveCallSite(IService service, ISet<Type> callSiteChain)
{
IServiceCallSite serviceCallSite = service.CreateCallSite(this, callSiteChain);
if (service.Lifetime == ServiceLifetime.Transient)
{
return new TransientCallSite(serviceCallSite);
}
else if (service.Lifetime == ServiceLifetime.Scoped)
{
return new ScopedCallSite(service, serviceCallSite);
}
else
{
return new SingletonCallSite(service, serviceCallSite);
}
}
ServiceProvider
对于Service的CreateCallSite方法,之前我们已经介绍过,现在我们重点讲下ServiceProvider的GetServiceCallSite方法。从上面代码中我们发现参数中含有“ ISet<Type> callSiteChain”,这个参数是防止发生A的构造函数有B类型参数,B的构织函数中有A类型参数,当A,B都是通过类型注入的,那么系统会陷入死循环。而callSiteChain得作用就是防止这样的死循环发生,当创建A时,会在callSiteChain中查询历史中是否有A的创建过程,如果有则说明发生死循环了,直接抛出异常,结束;如果没有将A加入到callSiteChain中,继续创建其参数。GetResolveCallSite方法比较简单,对于ServiceProvider已经能够获取的IServiceCallSite实例,进行包装,已保证生成的实例能够适应不同的Scoped(该处应该使用设计模式中的代理模式,不过我设计模式不过关,请帮忙确认)。
对于TransientCallSite、ScopedCallSite、SingletonCallSite以及EmptyIEnumerableCallSite代码,如下所示:
private class EmptyIEnumerableCallSite : IServiceCallSite
{
private readonly object _serviceInstance;
private readonly Type _serviceType; public EmptyIEnumerableCallSite(Type serviceType, object serviceInstance)
{
_serviceType = serviceType;
_serviceInstance = serviceInstance;
} public object Invoke(ServiceProvider provider)
{
return _serviceInstance;
} public Expression Build(Expression provider)
{
return Expression.Constant(_serviceInstance, _serviceType);
}
} private class TransientCallSite : IServiceCallSite
{
private readonly IServiceCallSite _service; public TransientCallSite(IServiceCallSite service)
{
_service = service;
} public object Invoke(ServiceProvider provider)
{
return provider.CaptureDisposable(_service.Invoke(provider));
} public Expression Build(Expression provider)
{
return Expression.Call(
provider,
CaptureDisposableMethodInfo,
_service.Build(provider));
}
} private class ScopedCallSite : IServiceCallSite
{
private readonly IService _key;
private readonly IServiceCallSite _serviceCallSite; public ScopedCallSite(IService key, IServiceCallSite serviceCallSite)
{
_key = key;
_serviceCallSite = serviceCallSite;
} public virtual object Invoke(ServiceProvider provider)
{
object resolved;
lock (provider._sync)
{
if (!provider._resolvedServices.TryGetValue(_key, out resolved))
{
resolved = provider.CaptureDisposable(_serviceCallSite.Invoke(provider));
provider._resolvedServices.Add(_key, resolved);
}
}
return resolved;
} public virtual Expression Build(Expression providerExpression)
{
var keyExpression = Expression.Constant(
_key,
typeof(IService)); var resolvedExpression = Expression.Variable(typeof(object), "resolved"); var resolvedServicesExpression = Expression.Field(
providerExpression,
"_resolvedServices"); var tryGetValueExpression = Expression.Call(
resolvedServicesExpression,
TryGetValueMethodInfo,
keyExpression,
resolvedExpression); var captureDisposableExpression = Expression.Assign(
resolvedExpression,
Expression.Call(
providerExpression,
CaptureDisposableMethodInfo,
_serviceCallSite.Build(providerExpression))); var addValueExpression = Expression.Call(
resolvedServicesExpression,
AddMethodInfo,
keyExpression,
resolvedExpression); var blockExpression = Expression.Block(
typeof(object),
new[] { resolvedExpression },
Expression.IfThen(
Expression.Not(tryGetValueExpression),
Expression.Block(captureDisposableExpression, addValueExpression)),
resolvedExpression); return Lock(providerExpression, blockExpression);
} private static Expression Lock(Expression providerExpression, Expression body)
{
// The C# compiler would copy the lock object to guard against mutation.
// We don't, since we know the lock object is readonly.
var syncField = Expression.Field(providerExpression, "_sync");
var lockWasTaken = Expression.Variable(typeof(bool), "lockWasTaken"); var monitorEnter = Expression.Call(MonitorEnterMethodInfo, syncField, lockWasTaken);
var monitorExit = Expression.Call(MonitorExitMethodInfo, syncField); var tryBody = Expression.Block(monitorEnter, body);
var finallyBody = Expression.IfThen(lockWasTaken, monitorExit); return Expression.Block(
typeof(object),
new[] { lockWasTaken },
Expression.TryFinally(tryBody, finallyBody));
}
} private class SingletonCallSite : ScopedCallSite
{
public SingletonCallSite(IService key, IServiceCallSite serviceCallSite) : base(key, serviceCallSite)
{
} public override object Invoke(ServiceProvider provider)
{
return base.Invoke(provider._root);
} public override Expression Build(Expression provider)
{
return base.Build(Expression.Field(provider, "_root"));
}
}
该工程所有类的关系图(包括内部类以及一些接口),如下所示:

补充说明
- IServiceCallSite中定义了Build方法,该方法使用了Expression,但是该篇文章没有对其进行具体的研究,并且Build方法是相对独立的。
- 对于OpenIEnumerableService泛型省略详解。
示例测试代码:
public static class TestServices
{
public static IServiceCollection DefaultServices()
{
var services = new ServiceCollection(); services.AddTransient<IFakeService, FakeService>();
services.AddTransient<IFakeMultipleService, FakeOneMultipleService>();
services.AddTransient<IFakeMultipleService, FakeTwoMultipleService>();
services.AddTransient<IFakeOuterService, FakeOuterService>();
services.AddInstance<IFakeServiceInstance>(new FakeService() { Message = "Instance" });
services.AddScoped<IFakeScopedService, FakeService>();
services.AddSingleton<IFakeSingletonService, FakeService>();
services.AddTransient<IDependOnNonexistentService, DependOnNonexistentService>();
services.AddTransient<IFakeOpenGenericService<string>, FakeService>();
services.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); services.AddTransient<IFactoryService>(provider =>
{
var fakeService = provider.GetService<IFakeService>();
return new TransientFactoryService
{
FakeService = fakeService,
Value =
};
}); services.AddScoped(provider =>
{
var fakeService = provider.GetService<IFakeService>();
return new ScopedFactoryService
{
FakeService = fakeService,
};
}); services.AddTransient<ServiceAcceptingFactoryService, ServiceAcceptingFactoryService>();
return services;
}
} public class ServiceProviderContainerTests : ScopingContainerTestBase
{
protected override IServiceProvider CreateContainer()
{
return TestServices.DefaultServices().BuildServiceProvider();
} [Fact]
public void ScopedServiceCanBeResolved()
{
IServiceProvider container = CreateContainer(); var scopeFactory = container.GetService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var containerScopedService = container.GetService<IFakeScopedService>();
var scopedService1 = scope.ServiceProvider.GetService<IFakeScopedService>();
Thread.Sleep();
var scopedService2 = scope.ServiceProvider.GetService<IFakeScopedService>(); Assert.NotEqual(containerScopedService, scopedService1);
Assert.Equal(scopedService1, scopedService2);
}
}
}
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)的更多相关文章
- [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-微软的实现(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项目代码分析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编译工具的可 ...
随机推荐
- C#实现的等额本息法、按月付息到期还本法、一次性还本付息法
你若懂行,那便有用,如下: void Main(){ var x = DengEBenXi.Compute(11111, 12, 3); x.Dump(); var y = AnYu ...
- js 倒计时实现
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Windows上帝模式,上帝应该就是这样使用Windows的
Windows上帝模式(Windows Master Control Panel)由来已久,最早是从Win7优化大湿里看到的一个选项,开启后在桌面生成一个图标,点进去后里面包含了几乎全部Windows ...
- 在 Win10 命令行使用 Consolas + 微软雅黑
这个过程挺神奇的,步骤参考了下面两篇文章,但是过程很曲折: 1. 使用Monaco和微软雅黑字体美化cmd和PowerShell 2. [zz]Windows的cmd.exe使用consolas加中文 ...
- sonne_game网站开发02spring+mybatis框架搭建
从最开始搭框架谈起,而且,我不仅仅会讲how,还会努力讲why.因为对于web开发,由于有太多好的框架.组件.工具,使得how往往不是那么深刻,背后的why更值得专研.如果有初学者关注我这个系列,也一 ...
- redis中使用redis-dump导出、导入、还原数据实例
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/109.html?1455861283 redis的备份和还原,借助了第三方 ...
- CCNA基础 IP地址子网划分
计算机是一个非常神奇的物品,它的核心算法是凌驾于任何代码架构.然而互联网网络( Internat )作为整个生态的基础资源.什么?你还不会子网划分? 没关系,看到子网掩码不要怕.因为它无非就是问你 & ...
- 快速入门系列--MVC--01概述
虽然使用MVC已经不少年,相关技术的学习进行了多次,但是很多技术思路的理解其实都不够深入.其实就在MVC框架中有很多设计模式和设计思路的体现,例如DependencyResolver类就包含我们常见的 ...
- 那些年我们写过的T-SQL(中篇)
中篇的重点在于,在复杂情况下使用表表达式的查询,尤其是公用表表达式(CTE),也就是非常方便的WITH AS XXX的应用,在SQL代码,这种方式至少可以提高一倍的工作效率.此外开窗函数ROW_NUM ...
- javaweb -- 获取请求IP(附实现源码)
实现步骤如下: (1)新建一个java web工程 (2)新建servers包,新建类GetRequestIp,用来处理获取请求IP,GetRequestIp类完整代码如下: package serv ...