Autofac 是一个轻量级的依赖注入(DI)框架,它可以帮助 .NET 开发人员更好地管理对象的生命周期和依赖关系。Autofac 可以大大简化应用程序中对象之间的耦合,使代码更加可维护和可测试。
Autofac 的主要特点:
轻量级:Autofac 是一个非常轻量级的框架,其核心库只有几个 DLL 文件。这意味着它可以很容易地与其他框架集成,并且对应用程序的性能没有任何影响。
灵活性:Autofac 提供了多种不同的注册方式,如 XML 配置文件、代码配置和属性注解等。开发人员可以根据自己的需求选择最适合的注册方式。
高性能:由于 Autofac 是一个轻量级框架,它的性能非常高。在实例化对象时,Autofac 可以比其他 DI 框架更快地找到并创建所需的依赖项。
生命周期管理:Autofac 提供了多种不同的生命周期管理选项,如瞬态(Transient)、作用域(Scoped)和单例(Singleton)等。这使得开发人员可以更好地控制对象的生命周期,有效地降低内存使用和提高性能。
AOP 支持:Autofac 可以轻松地与 AOP 框架集成,如 Castle DynamicProxy 等。这使得开发人员可以很容易地实现诸如事务管理、缓存和验证等方面的横切关注点。
Autofac 其核心思想是将对象之间的依赖关系从应用程序中分离出来。相对于传统的实例化对象方式,DI 可以有效地降低代码的耦合度,提高可维护性和可测试性。
Autofac 的架构主要分为两个部分:注册器(ContainerBuilder)和容器(IContainer)。注册器用于注册应用程序中所有需要注入的服务和组件,而容器则用于创建和管理这些组件实例。
注入方式
先准备点代码
接口层代码:粘贴太麻烦了,直接贴图,代码也很简单
猫的接口
狗的接口
猪的接口
技能接口
人的接口
实现层代码:粘贴太麻烦了,直接贴图,代码也很简单
猫的实现
狗的实现
猪的实现
人的实现
上面代码准备好了。我们搞注入
构造函数注入 (默认的注入方式)
{
//构造函数注入
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<PersonService>().As<IPersonService>();
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.Say();
p.PlayerWithDog();
}
上面代码通过RegisterType引入IDogService,后引入IPersonService,会执行PersionService中有一个IDogService作为参数的构造函数
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<PigService>().As<IPigService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<PersonService>().As<IPersonService>();
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.Say();
p.PlayerWithDog();
}
上面代码通过RegisterType引入了IDogService、ICatService、IPigService,因此会走具有三个参数的构造函数
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
//通过UsingConstructor方法指定要执行的构造函数
builder.RegisterType<PersonService>().As<IPersonService>().UsingConstructor(typeof(IDogService), typeof(ICatService));
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.Say();
p.PlayerWithDog();
p.PlayerWithCat();
}
上面代码通过RegisterType引入了IDogService、ICatService、再通过UsingConstructor方法指定要执行的构造函数,因此会走具有二个参数的构造函数
属性注入
准备代码,简单代码直接贴图
动物接口
动物实现
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<PigService>().As<IPigService>();
//PropertiesAutowired 使AnimalService实例的属性可以被注入
builder.RegisterType<AnimalService>().As<IAnimalService>().PropertiesAutowired();
IContainer container = builder.Build();
var p = container.Resolve<IAnimalService>();
p.Say();
}
上面代码 调用PropertiesAutowired 方法,使AnimalService实例的属性可以被注入
属性注入(属性注入选择器)
自定义一个空的特性
自定义属性选择器
动物实现2
{
//属性注入 属性注入选择器
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<PigService>().As<IPigService>();
//PropertiesAutowired 使AnimalService2实例的属性可以被注入
builder.RegisterType<AnimalService2>().As<IAnimalService>().PropertiesAutowired(new IoctAttributeSelector());
IContainer container = builder.Build();
var p = container.Resolve<IAnimalService>();
p.Say();
}
上面代码 调用PropertiesAutowired(new IoctAttributeSelector()) 方法,使AnimalService2实例的属性可以被选择注入
方法注入
所谓方法注入是指:在接口对象构造后,自动调用对象的某个方法
{
//方法注入 所谓方法注入是指:在接口对象构造后,自动调用对象的某个方法
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<PigService>().As<IPigService>();
builder.RegisterType<AnimalService>().As<IAnimalService>().OnActivated(Activator =>
{
var dogService = Activator.Context.Resolve<IDogService>();
var catService = Activator.Context.Resolve<ICatService>();
var pigService = Activator.Context.Resolve<IPigService>();
Activator.Instance.Play(catService, dogService, pigService);
});
IContainer container = builder.Build();
//构建IAnimalService对象,触发上述Play方法执行
var p = container.Resolve<IAnimalService>();
}
上面代码,构造了AnimalService的实例后自动调用Play方法
单抽象多继承 通过加入key来识别
{
//单抽象多继承 通过加入key来识别即可,如下
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().Keyed<ISkillService>("dog");
builder.RegisterType<CatService>().Keyed<ISkillService>("cat");
builder.RegisterType<PigService>().Keyed<ISkillService>("pig");
IContainer container = builder.Build();
//这里是狗
var dog = container.ResolveKeyed<ISkillService>("dog");
dog.ReleaseSkills();
//这里是猫
var cat = container.ResolveKeyed<ISkillService>("cat");
cat.ReleaseSkills();
//这里是猪
var pig = container.ResolveKeyed<ISkillService>("pig");
pig.ReleaseSkills();
}
上面代码,猫、狗、猪分别用key标识来分别
泛型注入
先准备点代码,贴图
一个参数的泛型接口
两个参数的泛型接口
一个参数的实现
两个参数的实现
{
//泛型注入
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(GenericAService<>)).As(typeof(IGenericAService<>));
builder.RegisterGeneric(typeof(GenericBService<,>)).As(typeof(IGenericBService<,>));
IContainer container = builder.Build();
var p = container.Resolve<IGenericAService<Dog>>();
var name1 = p.GetFullName();
var p2 = container.Resolve<IGenericBService<Dog, Cat>>();
var name2 = p2.GetFullName();
}
通过程序集加载1
{
//通过程序集加载
ContainerBuilder builder = new ContainerBuilder();
Assembly assemblyInterface = Assembly.LoadFrom("ITestLibraryService.dll");
Assembly assemblyService = Assembly.LoadFrom("TestLibraryService.dll");
builder.RegisterAssemblyTypes(assemblyInterface, assemblyService).AsImplementedInterfaces();
IContainer container = builder.Build();
//PersonService 会执行参数多的构造函数
var p = container.Resolve<IPersonService>();
p.PlayerWithDog();
p.PlayerWithCat();
p.PlayerWithPig();
}
这里需要说明的是,如果构造函数中有相同参数个数的构造函数,AutoFac会报错,他就不知道该执行哪个构造函数了。
通过程序集加载2
{
//通过程序集加载
ContainerBuilder builder = new ContainerBuilder();
Assembly iService = Assembly.Load("ITestLibraryService");
Assembly service = Assembly.Load("TestLibraryService");
builder.RegisterAssemblyTypes(iService, service).Where(p => p.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.PlayerWithDog();
p.PlayerWithCat();
p.PlayerWithPig();
}
上面代码,规定了名称必须是Service结尾的
接下来我们聊一聊WebApi中如何使用Autofac 框架
Nuget 先引用几个包
引用
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
<PackageReference Include="Castle.Core" Version="5.1.1" />
</ItemGroup>
Program 添加如下代码
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>((builder) =>
{
var controllersTypesInAssembly = typeof(Program).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(); //控制器支持属性注入
builder.RegisterGeneric(typeof(GenericAService<>)).As(typeof(IGenericAService<>));
builder.RegisterGeneric(typeof(GenericBService<,>)).As(typeof(IGenericBService<,>));
Assembly iService = Assembly.Load("ITestLibraryService");
Assembly service = Assembly.Load("TestLibraryService");
builder.RegisterAssemblyTypes(iService, service).Where(p => p.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
});
控制器就可以使用了
控制器代码
生命周期的管理
InstancePerDependency 瞬时
builder.RegisterType<TestAService>().As<ITestAService>().InstancePerDependency();
InstancePerLifetimeScope() 范围
builder.RegisterType<TestBService>().As<ITestBService>().InstancePerLifetimeScope();
InstancePerMatchingLifetimeScope("name名称") *匹配 name* 声明周期范围实例
builder.RegisterType<TestDService>().As<ITestDService>().InstancePerMatchingLifetimeScope("myscope");
SingleInstance 单例
builder.RegisterType<TestCService>().As<ITestCService>().SingleInstance();
AOP Castle DynamicProxy 动态代理 面向切片编程
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace CastleDynamicProxyDemo
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// ...
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>((builder) =>
{
var controllersTypesInAssembly = typeof(Program).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(); //控制器支持属性注入
builder.RegisterType<SimpleService>().As<ISimpleService>()
.EnableInterfaceInterceptors().InterceptedBy(typeof(LogInvocationInterceptor));
builder.RegisterType<LogInvocationInterceptor>().SingleInstance();
});
var app = builder.Build();
//.....
app.Run();
}
}
}
拦截器
using Castle.DynamicProxy;
namespace CastleDynamicProxyDemo
{
public class LogInvocationInterceptor : IInterceptor
{
private readonly ILogger<LogInvocationInterceptor> _logger;
public LogInvocationInterceptor(ILogger<LogInvocationInterceptor> logger)
{
_logger = logger;
}
public void Intercept(IInvocation invocation)
{
PrevProceed(invocation);
Proceed(invocation);
AfterProceed(invocation);
}
/// <summary>
/// 继续执行
/// </summary>
/// <param name="invocation"></param>
protected virtual void Proceed(IInvocation invocation)
{
//继续,这句是真的调用服务的方法
invocation.Proceed();
}
/// <summary>
/// 执行前
/// </summary>
/// <param name="invocation"></param>
protected virtual void PrevProceed(IInvocation invocation)
{
_logger.LogInformation(invocation.Method.Name);
_logger.LogInformation(#34;{invocation.Arguments}");
}
/// <summary>
/// 执行后
/// </summary>
/// <param name="invocation"></param>
protected virtual void AfterProceed(IInvocation invocation)
{
_logger.LogInformation(invocation.ReturnValue.ToString());
}
}
}
一个简单的服务
服务的实现
控制器调用
调试下执行过程
执行前
执行
执行后