.NET IoC 容器(三)Autofac
目录
- .NET IoC 容器(三)Autofac
- Autofac
- Nuget 安装
- 实现DI
- 定义接口
- 定义实现类
- 依赖注入
- 注入方式
- 构造函数注入 | 属性注入 | 方法注入
- 注入实现
- 接口注册
- 重复注册
- 指定参数注册
- 生命周期
- 默认生命周期
- 单例生命周期
- 每个周期范围一个生命周期
- 依赖配置
- Nuget
- 配置文件
- AOP
- Nuget安装
- 定义接口、实现类
- 定义切面
- 容器配置
- 参考资料
.NET IoC 容器(三)Autofac
Autofac
Autofac 是一个用于 .NET 应用程序的依赖注入 (Dependency Injection, DI) 容器。它帮助开发人员管理对象的创建和生命周期,使得依赖项的注入更加灵活和可维护。以下是 Autofac 的主要功能和特性概述:
依赖注入 (Dependency Injection)
Autofac 允许你通过构造函数、属性或方法注入依赖项。这样,你可以轻松地将对象的依赖关系传递给需要它们的类,从而提高代码的可测试性和可维护性。
模块化设计 (Modular Design)
Autofac 支持模块化设计,可以将相关的依赖项注册逻辑分组到模块中。这使得大型应用程序的配置更加简洁和易于管理。
生命周期管理 (Lifecycle Management)
Autofac 提供多种对象生命周期管理方式,例如单例 (Singleton)、每次请求 (Instance Per Dependency)、每个生命周期范围 (Instance Per Lifetime Scope) 等,允许你精确控制对象的创建和销毁时机。
注册与解析 (Registration and Resolution)
Autofac 通过流畅的 API 提供了多种注册组件的方式。你可以注册类型、实例、工厂方法,甚至通过扫描程序集自动注册组件。此外,Autofac 的解析功能支持构造函数参数注入、命名参数注入等高级特性。
支持 AOP (Aspect-Oriented Programming)
Autofac 与 AOP 框架(如 Castle Windsor)集成,支持横切关注点(如日志记录、事务管理)的处理,从而使业务逻辑代码更加简洁。
集成支持
Autofac 与许多流行的 .NET 库和框架集成良好,包括 ASP.NET Core、WCF、Web API、MVC 等。通过这些集成,Autofac 可以轻松地管理 web 应用程序中的依赖项。
扩展性
Autofac 具有很高的扩展性,可以通过自定义注册源、生命周期、解析器等方式扩展其功能,以满足特定应用的需求。
Nuget 安装
实现DI
定义接口
internal interface IComputer { }internal interface IKeyboard { }internal interface IMouse { }internal interface IPerson { IComputer Computer { get; set; } IKeyboard Keyboard { get; set; } IMouse Mouse { get; set; } void Work(); }定义实现类
internal class ConstructBase { public ConstructBase() { Console.WriteLine($"{this.GetType().Name} - 被构造了"); } }internal class LenovoComputer : ConstructBase, IComputer { public LenovoComputer() : base() { } }internal class TogarKeyboard : ConstructBase, IKeyboard { public TogarKeyboard() : base() { } }internal class LogitechMouse : ConstructBase, IMouse { public LogitechMouse() : base() { } }internal class Programmer : ConstructBase, IPerson { public IComputer Computer { get; set; } public IKeyboard Keyboard { get; set; } public IMouse Mouse { get; set; } public Programmer(IComputer computer, IKeyboard keyboard, IMouse mouse) : base() { Computer = computer; Keyboard = keyboard; Mouse = mouse; } public void Work() { Console.WriteLine("Programmers are building software..."); } }依赖注入
var builder = new ContainerBuilder(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); var container = builder.Build(); IPerson programmer = container.Resolve(); programmer.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 Zhy.IoC.Autofac.Programmer - 被构造了 Programmers are building software...
注入方式
构造函数注入 | 属性注入 | 方法注入
定义特性用来筛选属性注入
public class InjectPropertyAttribute : Attribute { }定义实现类
public class Gamer : ConstructBase, IPerson { public IComputer Computer { get; set; } [InjectProperty] public IKeyboard Keyboard { get; set; } public IMouse Mouse { get; set; } public Gamer(IComputer computer) : base() { Computer = computer; } public void Inject(IMouse mouse) { Mouse = mouse; } public void Work() { Console.WriteLine("The player is playing..."); } }注入实现
// 注入顺序(与编码顺序无关):构造函数注入 > 属性注入 > 方法注入 var builder = new ContainerBuilder(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType() // 方法注入 .OnActivating(e => { IMouse mouse = e.Context.Resolve(); e.Instance.Inject(mouse); }) // 属性注入 .PropertiesAutowired((g, o) => g.Name == "Keyboard") // 构造函数注入 .UsingConstructor(typeof(IComputer)) .As(); var container = builder.Build(); IPerson gamer = container.Resolve(); gamer.Work();输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.Gamer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 The player is playing...
结果
注入顺序:构造函数注入 > 属性注入 > 方法注入
接口注册
重复注册
var builder = new ContainerBuilder(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType() // 方法注入 .OnActivating(e => { IMouse mouse = e.Context.Resolve(); e.Instance.Inject(mouse); }) // 属性注入 .PropertiesAutowired((g, o) => g.Name == "Keyboard") // 构造函数注入 .UsingConstructor(typeof(IComputer)) .As(); var container = builder.Build(); IPerson programmer = container.Resolve(); programmer.Work();输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.Gamer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 The player is playing...
调换Gamer和Programmer的注册顺序:
var builder = new ContainerBuilder(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType() // 方法注入 .OnActivating(e => { IMouse mouse = e.Context.Resolve(); e.Instance.Inject(mouse); }) // 属性注入 .PropertiesAutowired((g, o) => g.Name == "Keyboard") // 构造函数注入 .UsingConstructor(typeof(IComputer)) .As(); builder.RegisterType().As(); var container = builder.Build(); IPerson programmer = container.Resolve(); programmer.Work();输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 Zhy.IoC.Autofac.Programmer - 被构造了 Programmers are building software...
结论
同一接口多次注册时,后注册的会覆盖前面注册的,若需要实现多重注册,需要指定名称
var builder = new ContainerBuilder(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType() // 方法注入 .OnActivating(e => { IMouse mouse = e.Context.Resolve(); e.Instance.Inject(mouse); }) // 属性注入 .PropertiesAutowired((g, o) => g.Name == "Keyboard") // 构造函数注入 .UsingConstructor(typeof(IComputer)) .Named("person"); builder.RegisterType().Named("programmer"); var container = builder.Build(); IPerson programmer = container.ResolveNamed("programmer"); IPerson person = container.ResolveNamed("person"); programmer.Work(); person.Work();输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 Zhy.IoC.Autofac.Programmer - 被构造了 Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.Gamer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 Programmers are building software... The player is playing...
指定参数注册
修改接口
internal interface IMouse { string Type { get; set; } }修改实现类
internal class LogitechMouse : ConstructBase, IMouse { public LogitechMouse() : base() { } public LogitechMouse(string type) : base() { Type = type; } public string Type { get; set; } }注入
var builder = new ContainerBuilder(); builder.RegisterType().WithParameter("type","502").As(); var container = builder.Build(); IMouse mouse = container.Resolve(); Console.WriteLine("mouse type: " + mouse.Type);输出
Zhy.IoC.Autofac.LogitechMouse - 被构造了 mouse type: 502
生命周期
Instance Per Dependency(默认) 每次请求组件时都会创建一个新的实例。这是默认的生命周期管理模式。
builder.RegisterType().As();
Singleton 在整个容器生命周期内,只有一个实例。
builder.RegisterType().As().SingleInstance();
Instance Per Lifetime Scope 在每个生命周期范围内,共享一个实例。每个生命周期范围都会创建一个新的实例,但在该范围内共享该实例。
builder.RegisterType().As().InstancePerLifetimeScope();
Instance Per Matching Lifetime Scope 在特定的生命周期范围内共享实例,需要指定标记。
builder.RegisterType().As().InstancePerMatchingLifetimeScope("my-scope");Instance Per Request 通常用于 web 应用程序,在每个 HTTP 请求期间共享一个实例。
builder.RegisterType().As().InstancePerRequest();
Externally Owned 组件由外部代码管理生命周期,Autofac 不会在容器释放时释放该实例。
builder.RegisterType().As().ExternallyOwned();
Instance Per Dependency 每次依赖请求时都会创建一个新实例。
builder.RegisterType().As().InstancePerDependency();
默认生命周期
var builder = new ContainerBuilder(); builder.RegisterType().As(); var container = builder.Build(); IComputer computer0 = container.Resolve(); IComputer computer1 = container.Resolve(); Console.WriteLine("computer0: " + computer0.GetHashCode()); Console.WriteLine("computer1: " + computer1.GetHashCode()); Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.LenovoComputer - 被构造了 computer0: 32347029 computer1: 22687807 computer0 == computer1: False
单例生命周期
var builder = new ContainerBuilder(); builder.RegisterType().As().SingleInstance(); var container = builder.Build(); IComputer computer0 = container.Resolve(); IComputer computer1 = container.Resolve(); Console.WriteLine("computer0: " + computer0.GetHashCode()); Console.WriteLine("computer1: " + computer1.GetHashCode()); Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 computer0: 32347029 computer1: 32347029 computer0 == computer1: True
每个周期范围一个生命周期
var builder = new ContainerBuilder(); builder.RegisterType().As().InstancePerLifetimeScope(); var container = builder.Build(); IComputer computer0 = container.Resolve(); using (var scope = container.BeginLifetimeScope()) { IComputer computer1 = scope.Resolve(); IComputer computer2 = scope.Resolve(); Console.WriteLine("computer0: " + computer0.GetHashCode()); Console.WriteLine("computer1: " + computer1.GetHashCode()); Console.WriteLine("computer2: " + computer2.GetHashCode()); Console.WriteLine($"computer0 == computer1: {computer0 == computer1}"); Console.WriteLine($"computer1 == computer2: {computer1 == computer2}"); }输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.LenovoComputer - 被构造了 computer0: 32347029 computer1: 22687807 computer2: 22687807 computer0 == computer1: False computer1 == computer2: True
依赖配置
Nuget
配置文件
Json
{ "components": [ { "type": "Zhy.IoC.Autofac.LenovoComputer,Zhy.IoC.Autofac", "services": [ { "type": "Zhy.IoC.Core.IComputer,Zhy.IoC.Core" } ], "autoActivate": true, "instanceScope": "singleinstance" }, { "type": "Zhy.IoC.Autofac.TogarKeyboard,Zhy.IoC.Autofac", "services": [ { "type": "Zhy.IoC.Core.IKeyboard,Zhy.IoC.Core" } ], "autoActivate": true, "instanceScope": "singleinstance" }, { "type": "Zhy.IoC.Autofac.LogitechMouse,Zhy.IoC.Autofac", "services": [ { "type": "Zhy.IoC.Core.IMouse,Zhy.IoC.Core" } ], "parameters": { "places": 4 }, "autoActivate": true, "instanceScope": "singleinstance" }, { "type": "Zhy.IoC.Autofac.Programmer,Zhy.IoC.Autofac", "services": [ { "type": "Zhy.IoC.Core.IPerson,Zhy.IoC.Core" } ], "autoActivate": true, "instanceScope": "singleinstance" } ] }XML
Zhy.IoC.Autofac.LenovoComputer,Zhy.IoC.Autofac Zhy.IoC.Autofac.TogarKeyboard,Zhy.IoC.Autofac Zhy.IoC.Autofac.LogitechMouse,Zhy.IoC.Autofac Zhy.IoC.Autofac.Programmer,Zhy.IoC.Autofac
调用
var config = new ConfigurationBuilder(); config.AddJsonFile("DI-Autofac.json"); // config.AddXmlFile("DI-Autofac.xml"); var module = new ConfigurationModule(config.Build()); var builder = new ContainerBuilder(); builder.RegisterModule(module); var container = builder.Build(); IPerson programmer = container.Resolve(); programmer.Work();输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了 Zhy.IoC.Autofac.TogarKeyboard - 被构造了 Zhy.IoC.Autofac.LogitechMouse - 被构造了 Zhy.IoC.Autofac.Programmer - 被构造了 Programmers are building software...
AOP
Nuget安装
定义接口、实现类
public interface IMyService { void DoWork(); }public void DoWork() { Console.WriteLine("Doing work..."); }定义切面
using Castle.DynamicProxy; public class LoggingInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine($"Invoking method {invocation.Method.Name} at {DateTime.Now}"); invocation.Proceed(); Console.WriteLine($"Method {invocation.Method.Name} has completed at {DateTime.Now}"); } }容器配置
var builder = new ContainerBuilder(); builder.Register(c => new LoggingInterceptor()); builder.RegisterType() .As() .EnableInterfaceInterceptors() .InterceptedBy(typeof(LoggingInterceptor)); var container = builder.Build(); var service = container.Resolve(); service.DoWork();输出
Invoking method DoWork at 2024/5/30 16:49:34 Doing work... Method DoWork has completed at 2024/5/30 16:49:34
参考资料
IOC容器之Unity与AutoFac_unity autofac-CSDN博客
Autofac/src/Autofac at develop · autofac/Autofac (github.com)
控制容器的反转和依赖关系注入模式 (martinfowler.com)



