深入浅出:从零开始掌握 Autofac 的依赖注入技巧
目录
Autofac基本使用
构造函数注入使用
属性注入使用
方法注入使用
AOP扩展使用
Autofac基本使用
Autofac:是一个用于.NET应用程序的依赖注入(Dependency Injection,DI)容器,旨在通过控制对象的生命周期和依赖关系来促进松耦合、可测试和可扩展的代码结构,其官方文档:地址 :
使用Autofac首先需要在项目中进行安装,可以通过NuGet包管理器来安装,如下所示,接下来就开始对Autofac的基本使用方法来概述:
创建接口和实体类:首先定义需要依赖注入的接口和对应的实现类,如下所示:
namespace webapi_study.Common
{
public interface IDatabaseConnection
{
void Connect();
}
public class DatabaseConnection : IDatabaseConnection
{
public void Connect()
{
Console.WriteLine("Connected to the database.");
}
}
}
配置Autofac容器:创建一个Autofac容器来注册服务并在应用程序中使用依赖注入,如下所示:
namespace webapi_study.Common
{
public class AutofacTest
{
public static void Register()
{
// 01、创建容器构建器对象
var builder = new ContainerBuilder();
// 02、注册服务组件
builder.RegisterType<DatabaseConnection>().As<IDatabaseConnection>();
// 03、构建容器
var container = builder.Build();
// 04、解析服务
var service = container.Resolve<IDatabaseConnection>();
service.Connect(); // 输出: "Connected to the database."
}
}
}
然后在入口文件处调用我们的注册服务,可以看到日志中打印了我们的数据:
如果想同时注册多个服务的话,可以为多个不同的接口注册不同的实现:
构造函数注入使用
在Autofac中构造函数注入是最常见的依赖注入方式之一,通过构造函数注入Autofac会自动解析类构造函数中需要的依赖并将其注入到类的实例中,下面是如何通过构造函数注入来实现依赖注入的示例:
构造函数注入:首先我们创建一个类,它有一个需要注入的依赖项:
namespace webapi_study.Common
{
public interface IServiceA
{
void Execute();
}
public class ServiceA : IServiceA
{
public void Execute()
{
Console.WriteLine("ServiceA is running!");
}
}
public class Consumer
{
private readonly IServiceA _serviceA;
// 通过构造函数注入
public Consumer(IServiceA serviceA)
{
_serviceA = serviceA;
}
public void Run()
{
_serviceA.Execute();
}
}
}
注册服务并注入解析:接下来我们使用Autofac注册ServiceA和Consumer并通过构造函数注入来自动解析IServiceA,如下所示:
namespace webapi_study.Common
{
public class AutofacTest
{
public static void Register()
{
// 01、创建容器构建器对象
var builder = new ContainerBuilder();
// 02、注册多个服务组件
builder.RegisterType<ServiceA>().As<IServiceA>();
builder.RegisterType<Consumer>(); // 注册Consumer(它会自动通过构造函数注入IServiceA)
// 03、构建容器
var container = builder.Build();
// 04、解析服务
var consumer = container.Resolve<Consumer>();
consumer.Run();
}
}
}
然后可以看到我们打印的语句仍然被执行了:
多个构造函数的注入:如果类有多个构造函数Autofac默认会注入参数最多的构造函数:
public class ConsumerWithMultipleConstructors
{
private readonly IServiceA _serviceA;
private readonly string _message;
// 构造函数1
public ConsumerWithMultipleConstructors(IServiceA serviceA)
{
_serviceA = serviceA;
_message = "Default Message";
}
// 构造函数2
public ConsumerWithMultipleConstructors(IServiceA serviceA, string message)
{
_serviceA = serviceA;
_message = message;
}
public void Run()
{
Console.WriteLine(_message);
_serviceA.Execute();
}
}
如果希望明确指定使用某个构造函数,可以使用WithParameter或者WithParameters方法来指定构造函数的参数,如下所示:
builder.RegisterType<ServiceA>().As<IServiceA>();
builder.RegisterType<ConsumerWithMultipleConstructors>()
.WithParameter("message", "Custom Message");
var container = builder.Build();
var consumer = container.Resolve<ConsumerWithMultipleConstructors>();
consumer.Run();
// 输出:
// "Custom Message"
// "ServiceA is running!"
属性注入使用
属性注入:是依赖注入的另一种方式,其中依赖关系通过对象的属性而不是构造函数来注入,这种方式在某些场景下很有用,尤其是当你不能修改构造函数的情况下或者依赖关系可以在对象创建后注入。在Autofac中属性注入可以通过InjectProperties方法来实现,它允许在实例化对象后自动注入属性依赖,首先创建一个需要依赖注入的类并使用属性来接收依赖项:
public interface IServiceA
{
void Execute();
}
public class ServiceA : IServiceA
{
public void Execute()
{
Console.WriteLine("ServiceA is running!");
}
}
public class Consumer
{
public IServiceA ServiceA { get; set; } // 通过属性注入依赖
public void Run()
{
ServiceA.Execute();
}
}
注册和属性注入:接下来使用Autofac注册服务并使用InjectProperties来进行属性注入,其中的方法PropertiesAutowired会告诉Autofac自动注入属性,如果Consumer类中有一个公共属性Autofac会查找并自动注入它,如下所示:
var builder = new ContainerBuilder();
// 注册 `IServiceA` 与 `ServiceA`
builder.RegisterType<ServiceA>().As<IServiceA>();
// 注册 `Consumer` 并启用属性注入
builder.RegisterType<Consumer>().PropertiesAutowired();
var container = builder.Build();
// 从容器中解析 `Consumer`
var consumer = container.Resolve<Consumer>();
// 使用 `Consumer` 的 `Run` 方法
consumer.Run(); // 输出: "ServiceA is running!"
适用场景:
1)懒加载依赖:你可以在对象创建后再注入依赖,而不是在构造时立即注入
2)可选依赖:某些依赖关系不是每次都需要的,或者可以在对象初始化后再注入
3)类的设计:如果你不能修改类的构造函数,可以考虑使用属性注入
方法注入使用
方法注入:是一种依赖注入的方式通过方法参数将依赖关系注入到类中而不是通过构造函数或属性,方法注入通常用于将依赖关系传递给需要的具体方法而不是整个类,在Autofac中方法注入可以通过使用WithParameter或OnActivated等方式来实现,如下:
定义服务和需要注入依赖的方法:假设你有一个类Consumer它需要一个服务IServiceA并通过方法来注入这个依赖:
public interface IServiceA
{
void Execute();
}
public class ServiceA : IServiceA
{
public void Execute()
{
Console.WriteLine("ServiceA is running!");
}
}
public class Consumer
{
public void Run(IServiceA serviceA) // 依赖注入通过方法参数传入
{
serviceA.Execute();
}
}
接下来使用Autofac配置和注册这些类,在解析Consumer时我们将IServiceA作为参数传递给Run方法,最后通过容器解析Consumer并手动调用Run方法同时传递需要的IServiceA实例:
var builder = new ContainerBuilder();
// 注册 IServiceA 和 ServiceA
builder.RegisterType<ServiceA>().As<IServiceA>();
// 注册 Consumer
builder.RegisterType<Consumer>();
var container = builder.Build();
// 从容器中解析 Consumer 实例
var consumer = container.Resolve<Consumer>();
// 手动注入 IServiceA 到 Run 方法
var serviceA = container.Resolve<IServiceA>();
consumer.Run(serviceA); // 输出: "ServiceA is running!"
另外Autofac也支持通过OnActivated来在对象激活后注入方法依赖,这种方式是在对象创建后自动执行某些方法:
builder.RegisterType<Consumer>()
.OnActivated(e =>
{
var serviceA = e.Context.Resolve<IServiceA>();
e.Instance.Run(serviceA); // 依赖注入到方法
});
适用场景:
1)临时依赖关系:如果某些依赖只在特定方法调用时才需要,可以使用方法注入
2)不需要全局依赖的场景:在某些任务处理方法中注入特定的服务而不需要为整个类注入
3)灵活控制依赖生命周期:方法注入可以更灵活地控制依赖注入的时机和范围
AOP扩展使用
在Autofac中AOP(面向切面编程)主要通过拦截器来实现,AOP允许在不修改原始代码的情况下在方法执行前后进行处理,比如日志记录、性能监控、事务管理等,Autofac通过Intercept方法和IDisposable接口的实现来提供对方法的拦截从而实现AOP的功能,AOP实现步骤如下:
创建一个拦截器:拦截器是实现AOP的核心,它允许你定义在方法执行前后或抛出异常时的处理逻辑,拦截器实现了IInterceptor接口:
using Castle.DynamicProxy;
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// 在方法调用前执行
Console.WriteLine("Before method call");
// 执行实际方法
invocation.Proceed();
// 在方法调用后执行
Console.WriteLine("After method call");
}
}
定义目标接口和实现:需要定义一个接口和实现,拦截器将会拦截这个接口的方法:
public interface IMyService
{
void DoWork();
}
public class MyService : IMyService
{
public void DoWork()
{
Console.WriteLine("Doing work...");
}
}
注册拦截器和目标类型:通过Autofac注册类型并指定拦截器,在Autofac中可以使用InterceptedBy方法来指定拦截器,最后使用容器解析目标对象时拦截器将自动被应用:
var builder = new ContainerBuilder();
// 注册 MyInterceptor
builder.RegisterType<MyInterceptor>();
// 注册目标类型并应用拦截器
builder.RegisterType<MyService>()
.As<IMyService>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(MyInterceptor));
var container = builder.Build();
var service = container.Resolve<IMyService>();
service.DoWork(); // 输出: Before method call -> Doing work... -> After method call
AOP的生命周期管理:Autofac支持通过生命周期管理来确保拦截器或被拦截的服务的生命周期符合你的需求,比如可以使用InstancePerLifetimeScope来确保在同一个生命周期中使用相同的实例:
builder.RegisterType<MyService>()
.As<IMyService>()
.InstancePerLifetimeScope() // 控制生命周期
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(MyInterceptor));
常见的AOP用法:
1)日志记录:在方法执行前后记录日志。
2)事务管理:在方法执行前开始事务,方法执行后提交事务。
3)性能监控:记录方法执行时间。
4)权限检查:在方法执行前检查权限。