DI 容器源码解析
大约 11 分钟约 3281 字
DI 容器源码解析
简介
ASP.NET Core 的依赖注入容器是框架的核心基础。理解 IServiceCollection、IServiceProvider 和 ActivatorUtilities 的内部实现,有助于优化服务注册、避免常见陷阱,以及在需要时实现自定义 DI 扩展。
特点
服务注册机制
ServiceDescriptor
// ServiceDescriptor 描述一个服务的注册信息
// 包含:ServiceType、ImplementationType、Lifetime、Instance、Factory
// 三种注册方式
var services = new ServiceCollection();
// 1. 类型注册
services.AddTransient<IUserService, UserService>();
services.AddScoped<IUserService, UserService>();
services.AddSingleton<IUserService, UserService>();
// 2. 工厂注册
services.AddSingleton<IHttpClient>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
return new CustomHttpClient(config["ApiUrl"]);
});
// 3. 实例注册
services.AddSingleton<ICache>(new MemoryCache(new MemoryCacheOptions()));
// ServiceDescriptor 内部结构
public class ServiceDescriptor
{
public Type ServiceType { get; } // 服务类型
public Type? ImplementationType { get; } // 实现类型
public ServiceLifetime Lifetime { get; } // 生命周期
public object? ImplementationInstance { get; } // 单例实例
public Func<IServiceProvider, object>? ImplementationFactory { get; } // 工厂
// TryAdd 系列方法(不覆盖已有注册)
// services.TryAdd(descriptor);
// services.TryAddTransient<IUserService, UserService>();
// services.TryAddEnumerable(descriptor); // 避免重复注册同一实现
}
// 替换注册(用于测试或覆盖)
services.Replace(ServiceDescriptor.Singleton<IUserService, MockUserService>());
// 移除注册
services.RemoveAll<IUserService>();生命周期管理
// Singleton — 全局唯一实例(应用级别)
// Scoped — 每个 Scope 内唯一(请求级别)
// Transient — 每次解析创建新实例
// Singleton 的线程安全
// 如果 Singleton 有可变状态,需要自行确保线程安全
public class ThreadSafeSingleton
{
private readonly ConcurrentDictionary<string, object> _cache = new();
private readonly object _lock = new();
// ✅ 使用 ConcurrentDictionary
public object GetOrAdd(string key, Func<string, object> factory)
=> _cache.GetOrAdd(key, factory);
// ❌ 不安全的可变状态
// private List<string> _items = new(); // 多线程访问不安全
}
// Scoped 生命周期
// ASP.NET Core 中每个请求创建一个 Scope
// Scope 内的同类型服务共享同一实例
public class OrderService
{
private readonly IUnitOfWork _uow;
private readonly IOrderRepository _orderRepo;
public OrderService(IUnitOfWork uow, IOrderRepository orderRepo)
{
// 如果 uow 和 orderRepo 注册为 Scoped
// 同一请求中它们是同一个 Scope 的实例
_uow = uow;
_orderRepo = orderRepo;
}
}
// ⚠️ 陷阱:Scoped 被 Singleton 捕获(Captive Dependency)
// Singleton 服务依赖 Scoped 服务 → Scoped 变成 Singleton 的生命周期!
public class BadSingleton
{
public BadSingleton(ScopedService scoped)
{
// scoped 在整个应用生命周期内不会被释放!
// 应该注入 IServiceProvider 并在需要时 CreateScope
}
}
// ✅ 正确做法:使用 IServiceProvider
public class GoodSingleton
{
private readonly IServiceProvider _sp;
public GoodSingleton(IServiceProvider sp) => _sp = sp;
public void DoWork()
{
using var scope = _sp.CreateScope();
var scoped = scope.ServiceProvider.GetRequiredService<IScopedService>();
scoped.DoSomething();
// scope 结束时 scoped 被释放
}
}ServiceProvider 源码解析
服务解析流程
// ServiceProvider 内部结构(简化)
internal sealed class ServiceProvider : IServiceProvider, IDisposable, IAsyncDisposable
{
private readonly ServiceTable _table; // 服务注册表
private readonly ServiceProvider _root; // 根容器
private readonly bool _isScoped; // 是否是 Scope
// 解析流程:
// 1. 查找 ServiceDescriptor
// 2. 根据生命周期获取或创建实例
// 3. 缓存实例(Singleton/Scoped)
public object GetService(Type serviceType)
{
// 特殊类型处理
if (serviceType == typeof(IServiceProvider))
return this;
if (serviceType == typeof(IServiceScopeFactory))
return new ServiceScopeFactory(_table);
// 查找注册
var descriptor = _table[serviceType];
return descriptor.Lifetime switch
{
ServiceLifetime.Singleton => GetSingleton(descriptor),
ServiceLifetime.Scoped => GetScoped(descriptor),
ServiceLifetime.Transient => CreateInstance(descriptor),
_ => throw new ArgumentOutOfRangeException()
};
}
private object GetSingleton(ServiceDescriptor descriptor)
{
// 根容器缓存 Singleton
if (descriptor.ImplementationInstance != null)
return descriptor.ImplementationInstance;
// 双检锁 + ConcurrentDictionary
return _root._singletons.GetOrAdd(descriptor, d => CreateInstance(d));
}
private object GetScoped(ServiceDescriptor descriptor)
{
// 当前 Scope 缓存
return _scopedInstances.GetOrAdd(descriptor, d => CreateInstance(d));
}
private object CreateInstance(ServiceDescriptor descriptor)
{
if (descriptor.ImplementationFactory != null)
return descriptor.ImplementationFactory(this);
// 使用编译的表达式树创建实例
var activator = CompileActivator(descriptor.ImplementationType!);
return activator(this);
}
}表达式树编译优化
// ServiceProvider 使用表达式树编译构造函数调用
// 避免反射的运行时开销
// 编译过程:
// 1. 查找构造函数(选择参数最多的)
// 2. 为每个参数生成解析表达式
// 3. 编译为 Func<IServiceProvider, object>
// 简化版编译器
Func<IServiceProvider, object> CompileActivator(Type implementationType)
{
var constructors = implementationType.GetConstructors();
var ctor = constructors
.OrderByDescending(c => c.GetParameters().Length)
.First();
var spParam = Expression.Parameter(typeof(IServiceProvider));
// 为每个参数生成 GetRequiredService 调用
var parameters = ctor.GetParameters()
.Select(p =>
{
var getServiceMethod = typeof(ServiceProviderServiceExtensions)
.GetMethod("GetRequiredService", new[] { typeof(IServiceProvider) })!
.MakeGenericMethod(p.ParameterType);
return (Expression)Expression.Call(getServiceMethod, spParam);
});
var newExpr = Expression.New(ctor, parameters);
var lambda = Expression.Lambda<Func<IServiceProvider, object>>(
Expression.Convert(newExpr, typeof(object)), spParam);
return lambda.Compile();
}
// ActivatorUtilities — 用于手动创建实例
// 当类型未注册到 DI 容器时使用
var instance = ActivatorUtilities.CreateInstance<UserService>(serviceProvider, "extra-param");
// UserService(IService1, IService2, string extraParam)
// IService1 和 IService2 从容器解析,extraParam 直接传入注入模式
构造函数注入最佳实践
// ✅ 推荐:明确的构造函数注入
public class OrderController : ControllerBase
{
private readonly IOrderService _orderService;
private readonly ILogger<OrderController> _logger;
public OrderController(IOrderService orderService, ILogger<OrderController> logger)
{
_orderService = orderService;
_logger = logger;
}
}
// ✅ 使用 required 成员(C# 11)+ 属性注入替代
public class MyService
{
[Inject] // 某些 DI 框架支持
public required IRepository Repository { get; init; }
}
// ✅ Keyed Services(.NET 8+)
builder.Services.AddKeyedSingleton<ICache, MemoryCache>("memory");
builder.Services.AddKeyedSingleton<ICache, RedisCache>("redis");
public class MyController(ICache defaultCache)
{
// 默认注入
}
public class MyController2([FromKeyedServices("redis")] ICache cache)
{
// 注入指定的 keyed service
}
// ✅ 从 IServiceProvider 解析(需要时才创建)
public class LazyService
{
private readonly IServiceProvider _sp;
private MyHeavyService? _heavy;
public LazyService(IServiceProvider sp) => _sp = sp;
public MyHeavyService Heavy => _heavy ??= _sp.GetRequiredService<MyHeavyService>();
}容器内部实现详解
ServiceProvider 解析流程
// ServiceProvider 内部结构(简化版)
// 1. 根容器(Root)— 创建时锁定所有 Singleton 注册
// 2. Scope 容器 — 每个 Scope 独立的实例缓存
// 3. ConcurrentDictionary — 线程安全的解析缓存
// 解析流程:
// Resolve<T>()
// → 查找 ServiceDescriptor
// → 检查缓存(Singleton 查根容器,Scoped 查当前 Scope)
// → 如果缓存命中,返回实例
// → 如果缓存未命中,创建实例
// → 调用构造函数(通过编译好的表达式树)
// → 注入依赖(递归解析)
// → 缓存实例(Singleton 存根容器,Scoped 存当前 Scope)
// → 如果实现了 IDisposable,注册到释放列表
// 表达式树编译(避免反射)
// 以下代码模拟 ServiceProvider 如何避免反射调用构造函数:
public static class ServiceProviderCompiler
{
// 缓存编译好的工厂委托
private static readonly ConcurrentDictionary<Type, Func<IServiceProvider, object>>
_factories = new();
public static Func<IServiceProvider, object> CompileFactory(Type serviceType)
{
return _factories.GetOrAdd(serviceType, type =>
{
// 查找合适的构造函数(参数最多的那个)
var constructors = type.GetConstructors();
var ctor = constructors.OrderByDescending(c => c.GetParameters().Length).First();
// 构建表达式树
var providerParam = Expression.Parameter(typeof(IServiceProvider), "provider");
var ctorParams = ctor.GetParameters().Select(p =>
{
// GetRequiredService(p.ParameterType)
var getServiceMethod = typeof(ServiceProviderServiceExtensions)
.GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService))!
.MakeGenericMethod(p.ParameterType);
return Expression.Call(providerParam, getServiceMethod);
}).ToArray();
var newExpr = Expression.New(ctor, ctorParams);
var convertExpr = Expression.Convert(newExpr, typeof(object));
// 编译为委托
return Expression.Lambda<Func<IServiceProvider, object>>(
convertExpr, providerParam).Compile();
});
}
}
// 验证:表达式树 vs 反射的性能差异
// 表达式树:编译一次,后续调用接近直接 new 的速度
// 反射:每次调用都需要查找和调用,性能差 10-100 倍Scope 生命周期管理
// IServiceScope 的内部实现
public class CustomScope : IServiceScope
{
private readonly Dictionary<ServiceDescriptor, object> _scopedInstances = new();
private readonly List<IDisposable> _disposables = new();
private bool _isDisposed;
public IServiceProvider ServiceProvider { get; }
public CustomScope(IServiceProvider rootProvider)
{
ServiceProvider = new ScopedServiceProvider(rootProvider, this);
}
public object GetOrCreateScoped(ServiceDescriptor descriptor)
{
if (_isDisposed)
throw new ObjectDisposedException(nameof(CustomScope));
if (_scopedInstances.TryGetValue(descriptor, out var instance))
return instance;
instance = descriptor.Lifetime switch
{
ServiceLifetime.Singleton => descriptor.GetRootInstance(),
ServiceLifetime.Scoped => CreateInstance(descriptor),
ServiceLifetime.Transient => CreateInstance(descriptor),
_ => throw new InvalidOperationException()
};
if (descriptor.Lifetime == ServiceLifetime.Scoped)
{
_scopedInstances[descriptor] = instance;
}
if (instance is IDisposable disposable)
{
_disposables.Add(disposable);
}
return instance;
}
private object CreateInstance(ServiceDescriptor descriptor)
{
// 实例化逻辑
return descriptor.ImplementationFactory?.Invoke(ServiceProvider)
?? Activator.CreateInstance(descriptor.ImplementationType!)!;
}
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
// 反序释放(后创建的先释放)
for (int i = _disposables.Count - 1; i >= 0; i--)
{
try
{
_disposables[i].Dispose();
}
catch (Exception ex)
{
Console.WriteLine($"释放 { _disposables[i].GetType().Name} 失败: {ex.Message}");
}
}
_scopedInstances.Clear();
_disposables.Clear();
}
}DI 调试与诊断
验证服务注册
// 启动时验证所有服务是否可以正确解析
public static class ServiceProviderValidator
{
public static void Validate(IServiceCollection services)
{
var serviceProvider = services.BuildServiceProvider();
var errors = new List<string>();
foreach (var descriptor in services)
{
try
{
if (descriptor.Lifetime == ServiceLifetime.Scoped)
{
using var scope = serviceProvider.CreateScope();
scope.ServiceProvider.GetService(descriptor.ServiceType);
}
else
{
serviceProvider.GetService(descriptor.ServiceType);
}
}
catch (Exception ex)
{
errors.Add($"解析 {descriptor.ServiceType.Name} 失败: {ex.Message}");
}
}
if (errors.Any())
{
Console.WriteLine("DI 验证错误:");
foreach (var error in errors)
{
Console.WriteLine($" - {error}");
}
}
else
{
Console.WriteLine("所有 DI 注册验证通过");
}
}
}
// 在开发环境自动验证
if (builder.Environment.IsDevelopment())
{
ServiceProviderValidator.Validate(builder.Services);
}打印依赖图
// 打印服务的依赖关系图
public static class DependencyGraphPrinter
{
public static void Print(IServiceCollection services)
{
Console.WriteLine("=== 服务依赖图 ===");
foreach (var descriptor in services.Where(d => d.ImplementationType != null))
{
var type = descriptor.ImplementationType!;
var ctors = type.GetConstructors();
if (ctors.Length > 0)
{
var mainCtor = ctors.OrderByDescending(c => c.GetParameters().Length).First();
var deps = mainCtor.GetParameters()
.Select(p => $"{p.ParameterType.Name} {p.Name}");
Console.WriteLine(
$"{descriptor.Lifetime,-10} {type.Name} → {string.Join(", ", deps)}");
}
}
}
}替代容器比较
Autofac vs Scrutor vs 内置容器
// Autofac 特性
// 1. 属性注入
// 2. 模块化注册(Module)
// 3. 拦截器(AOP)
// 4. 程序集扫描(更灵活)
// 5. 集合注册(IEnumerable<T>)
// Scrutor 特性(基于内置容器的扩展)
// 安装:Scrutor
builder.Services.Scan(scan => scan
.FromAssemblyOf<ApplicationService>()
.AddClasses(classes => classes.Where(t => t.Name.EndsWith("Service")))
.AsImplementedInterfaces()
.WithScopedLifetime()
);
// Scrutor 装饰器模式
builder.Services.Decorate<IOrderService, CachedOrderService>();
builder.Services.Decorate<IOrderService, LoggingOrderService>();
// 执行顺序:LoggingOrderService → CachedOrderService → OrderService
public class LoggingOrderService : IOrderService
{
private readonly IOrderService _inner;
private readonly ILogger<LoggingOrderService> _logger;
public LoggingOrderService(IOrderService inner, ILogger<LoggingOrderService> logger)
{
_inner = inner;
_logger = logger;
}
public Task<Order> GetByIdAsync(int id)
{
_logger.LogInformation("获取订单: {Id}", id);
return _inner.GetByIdAsync(id);
}
}
// 性能对比(解析 100 万次):
// 内置容器:~100ms(表达式树编译)
// Autofac:~120ms
// Scrutor:~130ms(装饰器有额外开销)
// Microsoft.Extensions.DependencyInjection:推荐大多数场景优点
缺点
缺点
总结
ASP.NET Core DI 通过 ServiceDescriptor 描述服务注册,支持类型、工厂和实例三种方式。ServiceProvider 使用表达式树编译构造函数调用,避免反射开销。Singleton 在根容器缓存,Scoped 在当前 Scope 缓存。核心陷阱:Singleton 不能直接依赖 Scoped 服务(Captive Dependency),应使用 IServiceProvider.CreateScope()。ActivatorUtilities 用于在容器外创建实例,支持混合 DI 和直接参数。.NET 8+ 的 Keyed Services 支持同类型多实现注入。
关键知识点
- 先分清这个主题位于请求链路、后台任务链路还是基础设施链路。
- 服务端主题通常不只关心功能正确,还关心稳定性、性能和可观测性。
- 任何框架能力都要结合配置、生命周期、异常传播和外部依赖一起看。
项目落地视角
- 画清请求进入、业务执行、外部调用、日志记录和错误返回的完整路径。
- 为关键链路补齐超时、重试、熔断、追踪和结构化日志。
- 把配置与敏感信息分离,并明确不同环境的差异来源。
常见误区
- 只会堆中间件或组件,不知道它们在链路中的执行顺序。
- 忽略生命周期和线程池、连接池等运行时资源约束。
- 没有监控和测试就对性能或可靠性下结论。
进阶路线
- 继续向运行时行为、可观测性、发布治理和微服务协同深入。
- 把主题和数据库、缓存、消息队列、认证授权联动起来理解。
- 沉淀团队级模板,包括统一异常处理、配置约定和基础设施封装。
适用场景
- 当你准备把《DI 容器源码解析》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合 API 服务、后台任务、实时通信、认证授权和微服务协作场景。
- 当需求开始涉及稳定性、性能、可观测性和发布流程时,这类主题会成为基础设施能力。
落地建议
- 先定义请求链路与失败路径,再决定中间件、过滤器、服务边界和依赖方式。
- 为关键链路补日志、指标、追踪、超时与重试策略。
- 环境配置与敏感信息分离,避免把生产参数写死在代码或镜像里。
排错清单
- 先确认问题发生在路由、模型绑定、中间件、业务层还是基础设施层。
- 检查 DI 生命周期、配置来源、序列化规则和认证上下文。
- 查看线程池、连接池、缓存命中率和外部依赖超时。
复盘问题
- 如果把《DI 容器源码解析》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《DI 容器源码解析》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《DI 容器源码解析》最大的收益和代价分别是什么?
