Dependency Injection(依赖注入DI)深度解析

从墨守成规到风骚走位,老张天天有问题在思考!

在这里插入图片描述


在这里插入图片描述

一、依赖注入核心原理与设计哲学

1.1 控制反转(IoC)与依赖注入(DI)
传统依赖管理
类主动创建依赖
紧耦合
IoC容器
类声明依赖
容器注入实现
松耦合

控制反转(IoC)是依赖注入的理论基础,其核心思想是将对象创建和依赖管理的控制权从应用程序代码转移到外部容器。依赖注入(DI)是IoC的具体实现方式,通过三种主要形式实现:

  • 构造函数注入
  • 方法注入
  • 属性注入
1.2 .NET DI 容器核心组件
public interface IServiceCollection
{
    IServiceCollection Add(ServiceDescriptor descriptor);
    // 注册服务的核心集合
}

public class ServiceDescriptor
{
    public Type ServiceType { get; }
    public Type ImplementationType { get; }
    public ServiceLifetime Lifetime { get; }
    // 定义服务生命周期的核心类
}

public enum ServiceLifetime
{
    Transient,  // 每次请求创建新实例
    Scoped,     // 同一作用域内单例
    Singleton   // 全局单例
}

二、依赖注入详细实现步骤

2.1 服务注册(Service Registration)
// 在Program.cs或Startup.cs中
var builder = WebApplication.CreateBuilder(args);

// 基础注册方式
builder.Services.AddTransient<IMyService, MyService>();       // 瞬时
builder.Services.AddScoped<IUserRepository, UserRepository>(); // 作用域
builder.Services.AddSingleton<ICacheService, CacheService>(); // 单例

// 高级注册方式
builder.Services.Add(new ServiceDescriptor(
    typeof(ILogger),
    provider => new FileLogger("app.log"),
    ServiceLifetime.Singleton));

// 泛型服务注册
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
2.2 服务解析(Service Resolution)
// 1. 构造函数注入(推荐)
public class OrderService
{
    private readonly IPaymentService _paymentService;
    
    public OrderService(IPaymentService paymentService)
    {
        _paymentService = paymentService;
    }
}

// 2. 方法注入
public class ReportGenerator
{
    public void Generate([FromKeyedServices("pdf")] IExportService exportService)
    {
        exportService.Export(reportData);
    }
}

// 3. 属性注入(慎用)
public class NotificationService
{
    [Inject] 
    public ILogger Logger { get; set; }
}

// 手动解析(在需要时)
using var scope = app.Services.CreateScope();
var service = scope.ServiceProvider.GetRequiredService<IMyService>();

三、七种依赖注入模式详解与对比

3.1 基础构造函数注入
public class ProductService
{
    private readonly IProductRepository _repository;
    private readonly ILogger _logger;

    public ProductService(
        IProductRepository repository, 
        ILogger<ProductService> logger)
    {
        _repository = repository;
        _logger = logger;
    }
}

优点

  • 强依赖明确声明
  • 对象初始化即完整状态
  • 天然支持不可变性

缺点

  • 构造函数参数过多时难以维护
  • 不支持可选依赖
3.2 方法注入
public class DataProcessor
{
    public void Process(IDataSource source, [FromServices] IValidator validator)
    {
        validator.Validate(source.GetData());
        // 处理逻辑
    }
}

适用场景

  • 依赖只在特定方法中使用
  • 避免构造函数膨胀
  • 需要运行时动态决定依赖
3.3 属性注入
public class ReportService
{
    [Inject]
    public IFormatter Formatter { get; set; }
}

风险警示

  • 对象可能处于不完整状态
  • 破坏封装性
  • 测试困难
  • .NET Core 默认不支持,需第三方容器
3.4 键控服务(Keyed Services)(.NET 8+)
// 注册
builder.Services.AddKeyedSingleton<IStorage, CloudStorage>("cloud");
builder.Services.AddKeyedSingleton<IStorage, LocalStorage>("local");

// 使用
public class BackupService([FromKeyedServices("cloud")] IStorage storage)
{
    public void Backup() => storage.Save(data);
}

优势

  • 同一接口多实现的管理
  • 运行时动态选择实现
  • 避免工厂模式复杂性
3.5 延迟解析(Lazy Resolution)
public class AnalyticsService(Lazy<IDataProcessor> processor)
{
    public void ProcessWhenNeeded()
    {
        if (condition) 
            processor.Value.Process(data);
    }
}

// 注册
builder.Services.AddTransient<IDataProcessor, DataProcessor>();
builder.Services.AddTransient(provider => 
    new Lazy<IDataProcessor>(provider.GetRequiredService<IDataProcessor>));

适用场景

  • 昂贵的依赖初始化
  • 条件执行的依赖
  • 解决循环依赖问题
3.6 选项模式(Options Pattern)
// 配置类
public class EmailOptions
{
    public const string Section = "Email";
    public string SmtpServer { get; set; }
    public int Port { get; set; }
}

// 注册
builder.Services.Configure<EmailOptions>(
    builder.Configuration.GetSection(EmailOptions.Section));

// 使用
public class EmailService(IOptions<EmailOptions> options)
{
    private readonly EmailOptions _opts = options.Value;
    
    public void Send() => /* 使用_opts.SmtpServer */
}
3.7 工厂模式
// 工厂接口
public interface IDbConnectionFactory
{
    IDbConnection Create(string connectionName);
}

// 实现
public class SqlConnectionFactory : IDbConnectionFactory
{
    private readonly IConfiguration _config;
    
    public SqlConnectionFactory(IConfiguration config) 
        => _config = config;

    public IDbConnection Create(string name) => 
        new SqlConnection(_config.GetConnectionString(name));
}

// 注册
builder.Services.AddSingleton<IDbConnectionFactory, SqlConnectionFactory>();

四、生命周期管理深度剖析

4.1 生命周期类型对比
生命周期创建时机适用场景典型陷阱
Transient每次请求无状态服务
轻量级对象
频繁创建开销大
内存泄漏风险
Scoped作用域内Web请求
事务操作
跨作用域访问错误
异步流污染
Singleton首次请求配置服务
缓存
并发安全问题
资源未释放
4.2 生命周期冲突解决方案

问题场景:Singleton 服务依赖 Scoped 服务

// 错误示例
builder.Services.AddSingleton<IBackgroundService, MyBackgroundService>();
builder.Services.AddScoped<IDbContext, AppDbContext>();

// 解决方案1:服务作用域
public class MyBackgroundService(IServiceProvider provider)
{
    public void Process()
    {
        using var scope = provider.CreateScope();
        var context = scope.ServiceProvider.GetRequiredService<IDbContext>();
        // 使用context
    }
}

// 解决方案2:延迟解析
public class MyBackgroundService(Lazy<IDbContext> context)
{
    public void Process() => context.Value.DoSomething();
}
4.3 释放机制与IDisposable
public class ResourceService : IDisposable
{
    private readonly FileStream _fileStream;

    public ResourceService()
    {
        _fileStream = File.Open("data.bin", FileMode.Open);
    }

    public void Dispose()
    {
        _fileStream?.Dispose();
        GC.SuppressFinalize(this);
    }
}

// 注册
builder.Services.AddScoped<ResourceService>();

// 容器自动调用Dispose
// Scoped:作用域结束时
// Transient:请求结束时
// Singleton:应用程序关闭时

五、高级应用场景

5.1 装饰器模式
// 基础服务
public interface IDataService
{
    string GetData();
}

// 核心实现
public class CoreDataService : IDataService { /*...*/ }

// 装饰器
public class CachingDecorator : IDataService
{
    private readonly IDataService _inner;
    private readonly ICache _cache;

    public CachingDecorator(IDataService inner, ICache cache)
    {
        _inner = inner;
        _cache = cache;
    }

    public string GetData() => 
        _cache.GetOrCreate("data-key", _inner.GetData);
}

// 注册(需第三方库如Scrutor)
builder.Services.AddScoped<IDataService, CoreDataService>();
builder.Services.Decorate<IDataService, CachingDecorator>();
5.2 动态代理(AOP实现)
public class LoggingProxy<T> : DispatchProxy
{
    private T _decorated;
    private ILogger _logger;

    protected override object Invoke(MethodInfo method, object[] args)
    {
        _logger.LogInformation($"调用 {method.Name}");
        try 
        {
            var result = method.Invoke(_decorated, args);
            _logger.LogInformation($"成功 {method.Name}");
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"失败 {method.Name}");
            throw;
        }
    }

    public static T Create(T decorated, ILogger logger)
    {
        object proxy = Create<T, LoggingProxy<T>>();
        ((LoggingProxy<T>)proxy).SetParameters(decorated, logger);
        return (T)proxy;
    }

    private void SetParameters(T decorated, ILogger logger)
    {
        _decorated = decorated;
        _logger = logger;
    }
}

// 注册
builder.Services.AddScoped<IService>(provider => 
    LoggingProxy<IService>.Create(
        new RealService(), 
        provider.GetRequiredService<ILogger>()));
5.3 多租户解决方案
// 租户识别
public interface ITenantProvider
{
    string GetCurrentTenant();
}

// 租户特定服务
public class TenantServiceFactory
{
    private readonly IServiceProvider _provider;
    private readonly ConcurrentDictionary<string, ITenantService> _cache = new();

    public TenantServiceFactory(IServiceProvider provider) 
        => _provider = provider;

    public ITenantService GetService()
    {
        var tenant = _provider.GetRequiredService<ITenantProvider>().GetCurrentTenant();
        return _cache.GetOrAdd(tenant, t => 
        {
            var scope = _provider.CreateScope();
            return scope.ServiceProvider.GetRequiredService<ITenantService>();
        });
    }
}

// 注册
builder.Services.AddScoped<ITenantProvider, HeaderTenantProvider>();
builder.Services.AddScoped<ITenantService, TenantSpecificService>();
builder.Services.AddSingleton<TenantServiceFactory>();

六、最佳实践与性能优化

6.1 依赖注入黄金法则
  1. 构造函数保持精简(≤5个依赖)
  2. 避免服务定位器反模式(谨慎使用IServiceProvider)
  3. 接口与实现1:1原则(除非明确需要多实现)
  4. 生命周期最短化(优先选择Transient)
  5. 避免循环依赖(重构为更高层协调)
6.2 性能优化策略
// 1. 减少构造函数复杂度
public class OptimizedService
{
    // 将多个相关依赖聚合
    private readonly ServiceBundle _bundle;

    public OptimizedService(ServiceBundle bundle) => _bundle = bundle;
}

public class ServiceBundle
{
    public ILogger Logger { get; }
    public IMapper Mapper { get; }
    public ICache Cache { get; }
    
    public ServiceBundle(ILogger l, IMapper m, ICache c) 
        => (Logger, Mapper, Cache) = (l, m, c);
}

// 2. 预编译服务解析
var services = new ServiceCollection();
services.AddSingleton<MyService>();
var serviceProvider = services.BuildServiceProvider();
var compiledProvider = serviceProvider.Compile(); // 第三方库

// 3. 避免反射开销(源生成器)
[ServiceConstructor]
public partial class GeneratedService
{
    private readonly ILogger _logger;
    private readonly IRepository _repo;
}

// 自动生成构造函数
partial class GeneratedService
{
    [ActivatorUtilitiesConstructor]
    public GeneratedService(ILogger logger, IRepository repo)
    {
        _logger = logger;
        _repo = repo;
    }
}

七、常见陷阱与解决方案

7.1 生命周期陷阱

症状

  • 内存泄漏
  • 数据跨请求污染
  • 对象状态异常

诊断工具

// 启用详细日志
builder.Services.AddLogging(b => 
    b.AddConsole().SetMinimumLevel(LogLevel.Debug));

// 检查服务生存期
var descriptor = builder.Services.FirstOrDefault(s => 
    s.ServiceType == typeof(IMyService));
Console.WriteLine($"Lifetime: {descriptor.Lifetime}");
7.2 循环依赖解决方案
// 问题代码
public class ServiceA(ServiceB b) { }
public class ServiceB(ServiceA a) { } // 循环依赖

// 解决方案1:方法注入
public class ServiceA
{
    private ServiceB _b;
    public void SetB(ServiceB b) => _b = b;
}

// 解决方案2:接口分离
public interface IServiceA { }
public interface IServiceB { }

public class ServiceA : IServiceA
{
    public ServiceA(IServiceB b) { } // 依赖接口
}

public class ServiceB : IServiceB
{
    public ServiceB(IServiceA a) { } // 依赖接口
}

// 容器可解析接口循环
7.3 多实现冲突解决
// 注册多个实现
builder.Services.AddScoped<IMessageService, SmsService>();
builder.Services.AddScoped<IMessageService, EmailService>();

// 解决方案1:获取所有实现
public class Notifier(IEnumerable<IMessageService> services)
{
    public void NotifyAll() => services.ToList().ForEach(s => s.Send());
}

// 解决方案2:命名注册(需第三方库)
builder.Services.AddKeyedScoped<IMessageService>("sms", SmsService);
builder.Services.AddKeyedScoped<IMessageService>("email", EmailService);

public class UserService(
    [FromKeyedServices("email")] IMessageService emailService)
{
    public void ResetPassword() => emailService.Send(...);
}

八、框架集成与扩展

8.1 ASP.NET Core 集成
// 控制器注入
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _service;
    
    public UsersController(IUserService service) => _service = service;

    [HttpGet("{id}")]
    public ActionResult<User> Get(int id) => _service.GetById(id);
}

// 视图注入
@inject IConfiguration Config
<p>Environment: @Config["Env"]</p>

// 中间件注入
public class LoggingMiddleware(RequestDelegate next, ILogger logger)
{
    public async Task Invoke(HttpContext context)
    {
        logger.LogRequest(context.Request);
        await next(context);
    }
}
8.2 控制台应用集成
var services = new ServiceCollection();
services.AddLogging(b => b.AddConsole());
services.AddScoped<MainService>();

using var provider = services.BuildServiceProvider();
using var scope = provider.CreateScope();

var service = scope.ServiceProvider.GetRequiredService<MainService>();
service.Run();
8.3 第三方容器对比
特性内置容器AutofacDryIocLamar
属性注入✔️✔️✔️
装饰器手动✔️✔️✔️
子容器✔️✔️
动态代理✔️
AOP支持✔️
性能极高
学习曲线

九、未来演进与趋势

9.1 源生成器优化
// 自动生成DI注册代码
[ServiceGenerator]
public interface IMyServices
{
    ILogger Logger { get; }
    IRepository Repo { get; }
}

// 编译时生成
public static class ServiceRegistration
{
    public static IServiceCollection AddMyServices(this IServiceCollection services)
    {
        services.AddScoped<ILogger, ConsoleLogger>();
        services.AddScoped<IRepository, SqlRepository>();
        return services;
    }
}
9.2 编译时依赖验证
// 编译时检查
[DependencyCheck]
public class OrderProcessor
{
    [RequiredDependency]
    private readonly IPaymentGateway _gateway;
    
    [OptionalDependency]
    private readonly ILogger _logger;
}

// 编译错误:缺少IPaymentGateway实现
9.3 云原生DI模式
// 动态配置绑定
builder.Services.Configure<CloudOptions>(
    context.Configuration.GetSection("Cloud"));

// 环境感知注册
if (builder.Environment.IsProduction())
{
    builder.Services.AddSingleton<IDataStore, CosmosDbStore>();
}
else
{
    builder.Services.AddSingleton<IDataStore, InMemoryStore>();
}

// 健康检查集成
builder.Services.AddHealthChecks()
    .AddCheck<DatabaseHealthCheck>("database")
    .AddCheck<CacheHealthCheck>("cache");

架构师箴言:依赖注入不是目标,而是实现可维护、可测试、松耦合系统的手段。真正的架构艺术在于平衡DI的便利性与系统的简洁性,避免陷入过度设计的深渊。当DI配置的复杂性超过业务逻辑复杂性时,就是重新评估架构的信号。
在这里插入图片描述

评论 114
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百锦再@新空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值