在 .NET 中使用 AutoFac 进行依赖关系注入

作者:微信公众号:【架构师老卢】
9-25 20:13
152

虽然在简单的应用程序中管理 DI 很简单,但在大型分布式系统中却变得具有挑战性。这就是 Autofac (一个强大的 .NET 库)简化依赖项管理的地方,让您的代码保持干净和健壮。

把它想象成制造一辆汽车——如果发动机、燃油系统和变速箱紧密耦合,更换一个部件将是一场噩梦。在软件中,紧密耦合的代码也存在类似的问题。DI 解决了这个问题,而 Autofac 使这个过程无缝衔接。在本文中,我将深入研究 Autofac 并探讨它如何帮助管理依赖项。

Autofac 简介

Autofac 是 .NET 的常用 IoC(控制反转)容器。它通过自动处理对象创建和生命周期管理来简化依赖项管理。Autofac 在复杂的应用程序中大放异彩,在这些应用程序中,您可能有数十个依赖项需要管理,从而使代码更简洁、更易于管理且更易于测试。

它负责解析所有依赖项,因此我们不必手动管理它们。

示例:制造汽车

考虑这个依赖发动机和燃料的汽车的简化示例。如果没有 DI,car 类将直接实例化这些对象,从而导致紧密耦合的代码。以下是使用 Autofax 时的区别:

无依赖关系注入

public class Car {  
    private Engine engine;  
    private Fuel fuel;  
  
    public Car() {  
        this.engine = new Engine();  
        this.fuel = new Fuel();  
    }  
}

这对于小型项目来说很好,但随着系统复杂性的增加,这种方法会变得很麻烦。对发动机或燃料等级的更改可能会破坏汽车等级。

使用依赖关系注入 (AutoFac)

public class Car {  
    private Engine engine;  
    private Fuel fuel;  
  
    public Car(Engine engine, Fuel fuel) {  
        this.engine = engine;  
        this.fuel = fuel;  
    }  
}  
  
  
// program.cs  
 IFuel fuel = new DieselFuel();  
 IEngine engine = new PetrolEngine(fuel);  
 Car car  = new(engine, fuel);  
 car.Drive();

现在,该类不需要知道如何创建引擎或燃料 — 它只需接收它们。使用 Autofac,我们可以轻松定义和解决这些依赖关系。Car

使用 Autofac:分步分解

在本节中,我们将通过一个简单的示例来介绍 Autofac 如何处理依赖项。

现在,我们正在使用依赖于 和 的 a。目标是使用 Autofac 注入这些依赖项,使代码灵活且易于维护。CarEngineFuel

使用 Autofac,依赖项通过容器进行管理,该过程遵循以下关键步骤:

  • 组件定义:定义必要的依赖关系(例如,Car、Engine、Fuel)。
  • 注册:向 Autofac 容器注册这些组件。
  • 依赖项解析:Autofac 会在需要时自动解析并注入所需的依赖项,从而解耦组件并提高灵活性。

例如,在 program.cs 文件中,您可以像这样使用 Autofac

var builder = new ContainerBuilder();

builder.RegisterType<DieselFuel>().As<IFuel>().InstancePerLifetimeScope();
builder.RegisterType<PetrolEngine>().As<IEngine>();
builder.RegisterType<Car>();

var container = builder.Build();

using (var scope = container.BeginLifetimeScope())
{
    var car = scope.Resolve<Car>();
    car.Drive();
}

让我们一步一步地看看它是如何实现的

1. 创建 Container Builder

var builder = new ContainerBuilder();
  • 此行将创建一个实例,该实例负责构建和配置 Autofac 容器。ContainerBuilder
  • ContainerBuilder 本质上是我们定义如何在应用程序中创建和管理依赖项(对象或服务)的地方。

2. 注册依赖项

builder.RegisterType<DieselFuel>().As<IFuel>().InstancePerLifetimeScope();
builder.RegisterType<PetrolEngine>().As<IEngine>();
builder.RegisterType<Car>();
  • RegisterType<DieselFuel>():这会告诉 Autofac 在需要 type 依赖项时使用该类作为实现。DieselFuelIFuel
  • .As<IFuel>():这表明无论在哪里请求,都应该提供。 是接口,是实现。DieselFuelIFuelIFuelDieselFuel
  • .InstancePerLifetimeScope():定义对象的生命周期。在这种情况下,将为每个生命周期范围 (通常是请求或操作) 创建一个新实例。这可确保在单个范围内共享相同的实例。DieselFuelDieselFuel

3. 构建容器

var container = builder.Build();
  • 此行构建容器,锁定所有注册。构建容器后,您将无法再添加新的注册。
  • 容器现在负责管理所有依赖项的生命周期和解析。

4. 创建生命周期范围

using (var scope = container.BeginLifetimeScope())
  • BeginLifetimeScope()创建新的生存期范围。此范围管理该范围内依赖项的解析和处置。
  • 在此示例中,我们将为特定操作创建范围。具有生命周期范围注册 (如 ) 的依赖项将在此范围内实例化和重用。DieselFuel

5. 解决依赖关系

var car = scope.Resolve<Car>();
  • scope.Resolve<Car>() 告诉 Autofac 创建并注入类所需的所有依赖项。Car
  • Autofac 查看类的构造函数,看到它需要 an 和 an ,并根据注册( for 和 for )解析这些依赖项。CarIEngineIFuelPetrolEngineIEngineDieselFuelIFuel
  • 解析后,实例将完全构建并注入其依赖项。Car

6. 使用已解析的对象

car.Drive();
  • 解析实例后,我们现在可以调用其方法(在本例中为 )。CarDrive()
  • 此时,所有依赖项都已注入,类可以按预期运行。Car

7. 范围

// scope.Dispose() happens automatically here due to the 'using' statement

  • 一旦不再需要 scope,它就会被自动释放(因为 block)。using
  • 这可确保正确清理与范围生命周期相关的任何资源,例如向 .InstancePerLifetimeScope()

此示例演示了 Autofac 如何以干净和结构化的方式管理依赖项。通过定义、注册和解析依赖项,我们将组件彼此解耦,使代码更加模块化、可维护和可测试。

使用 Autofac 管理对象生命周期

Autofac 提供的另一个重要功能是生命周期管理。无论您是希望每个请求都有一个对象的新实例,还是希望在整个应用程序中使用单个实例,Autofac 都允许您轻松定义这一点。

我们有多种方法可以注册具有不同生命周期的组件,例如:

  • Instance Per Dependency(每个依赖项的实例数):每次都会创建一个新实例。
  • 单个实例:单个实例在整个应用程序中共享。
  • Instance Per Lifetime Scope(每个生存期范围的实例数):为每个范围创建一个新实例。

Autofac 为在 .NET 应用程序中实现依赖项注入提供了强大的解决方案。

通过采用 Autofac,您可以在项目中实现更高程度的模块化和灵活性,随着时间的推移,这可以提高性能并简化维护。

相关留言评论
昵称:
邮箱:
阅读排行