Autofac详解
Autofac詳解
零、文章目錄
一、Autofac詳解
1、概述
- Autofac是第三方IOC容器,是當(dāng)前最流行的IOC容器。
- 功能強(qiáng)大,比asp.netcore內(nèi)置容器強(qiáng)大得多,支持屬性注入和方法注入,支持AOP。
- 官網(wǎng)地址:http://autofac.org/
- 源碼下載地址:https://github.com/autofac/Autofac
2、快速開始
(1)Nuget引入程序包
Autofac 基于版本6.3演示,Net5(2)容器創(chuàng)建對(duì)象
//創(chuàng)建一個(gè)容器建造者 ContainerBuilder containerBuilder = new ContainerBuilder(); //注冊(cè)普通類 containerBuilder.RegisterType<Honer>(); //build一下,得到一個(gè)容器 IContainer container = containerBuilder.Build(); //可以基于容器來獲取對(duì)象的實(shí)例 Honer phone = container.Resolve<Honer>();3、注冊(cè)的類型
(1)注冊(cè)普通類
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>(); IContainer container = containerBuilder.Build(); Honer phone = container.Resolve<Honer>();(2)注冊(cè)抽象與實(shí)現(xiàn)
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); IContainer container = containerBuilder.Build(); IPhone phone = container.Resolve<IPhone>();(3)注冊(cè)程序集
- RegisterAssemblyTypes(程序集數(shù)組),程序集必須是public的
- AsImplementedInterfaces():表示注冊(cè)的類型,以接口的方式注冊(cè)
- PropertiesAutowired():支持屬性注入
- Where:滿足條件類型注冊(cè)
4、三種注入方式
(1)構(gòu)造函數(shù)注入
默認(rèn)支持,無法用特性進(jìn)行篩選,默認(rèn)選參數(shù)最多的構(gòu)造函數(shù)進(jìn)行注入
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); containerBuilder.RegisterType<Teacher>().As<ITeacher>(); containerBuilder.RegisterType<Student>().As<IStudent>(); IContainer container = containerBuilder.Build(); ITeacher teacher = container.Resolve<ITeacher>();(2)全部屬性注入
關(guān)鍵詞PropertiesAutowired,這個(gè)對(duì)象所有屬性全部注入
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); containerBuilder.RegisterType<Teacher>().As<ITeacher>().PropertiesAutowired(); containerBuilder.RegisterType<Student>().As<IStudent>(); IContainer container = containerBuilder.Build(); ITeacher teacher = container.Resolve<ITeacher>();(3)標(biāo)記特性的屬性注入
關(guān)鍵詞PropertiesAutowired,定義特性選擇器CustomPropertySelector
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); containerBuilder.RegisterType<Teacher>().As<ITeacher>().PropertiesAutowired(new CustomPropertySelector()); containerBuilder.RegisterType<Student>().As<IStudent>(); IContainer container = containerBuilder.Build(); ITeacher teacher = container.Resolve<ITeacher>(); public class CustomPropertySelector : IPropertySelector {public bool InjectProperty(PropertyInfo propertyInfo, object instance){var flag = propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(SelectPropAttribute));return flag;} }(4)方法注入
關(guān)鍵詞OnActivated,指定調(diào)用方法
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); containerBuilder.RegisterType<Teacher>().As<ITeacher>().OnActivated(p =>{p.Instance.SetStudent1(p.Context.Resolve<IStudent>());}); containerBuilder.RegisterType<Student>().As<IStudent>(); IContainer container = containerBuilder.Build(); ITeacher teacher = container.Resolve<ITeacher>();5、對(duì)象生命周期
(1)瞬時(shí)生命周期
每次獲取都是全新的實(shí)例,關(guān)鍵詞InstancePerDependency,默認(rèn)的生命周期
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>().InstancePerDependency(); IContainer container = containerBuilder.Build(); IPhone phone1 = container.Resolve<IPhone>(); IPhone phone2 = container.Resolve<IPhone>(); bool isflg1 = object.ReferenceEquals(phone1, phone2); Console.WriteLine($"InstancePerDependency:phone1==phone2=>{isflg1}"); InstancePerDependency:phone1==phone2=>False(2)單例生命周期
同一個(gè)進(jìn)程內(nèi)都是同一個(gè)實(shí)例,關(guān)鍵詞SingleInstance
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>().SingleInstance(); IContainer container = containerBuilder.Build(); IPhone phone1 = container.Resolve<IPhone>(); IPhone phone2 = container.Resolve<IPhone>(); bool isflg1 = object.ReferenceEquals(phone1, phone2); Console.WriteLine($"SingleInstance:phone1==phone2=>{isflg1}"); using (var scope = container.BeginLifetimeScope()) {IPhone phone3 = scope.Resolve<IPhone>();IPhone phone4 = scope.Resolve<IPhone>();bool isflg2 = object.ReferenceEquals(phone3, phone4);Console.WriteLine($"SingleInstance:phone3==phone4=>{isflg2}");bool isflg3 = object.ReferenceEquals(phone1, phone3);Console.WriteLine($"SingleInstance:phone1==phone3=>{isflg3}"); } SingleInstance:phone1==phone2=>True SingleInstance:phone3==phone4=>True SingleInstance:phone1==phone3=>True(3)作用域生命周期
同一個(gè)作用域內(nèi)都是同一個(gè)實(shí)例,關(guān)鍵詞InstancePerLifetimeScope
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>().InstancePerLifetimeScope(); IContainer container = containerBuilder.Build(); IPhone phone1 = container.Resolve<IPhone>(); IPhone phone2 = container.Resolve<IPhone>(); bool isflg1 = object.ReferenceEquals(phone1, phone2); Console.WriteLine($"InstancePerLifetimeScope:phone1==phone2=>{isflg1}"); IPhone phone3 = null; IPhone phone4 = null; using (var scope = container.BeginLifetimeScope()) {phone3 = scope.Resolve<IPhone>();phone4 = scope.Resolve<IPhone>();bool isflg2 = object.ReferenceEquals(phone3, phone4);Console.WriteLine($"InstancePerLifetimeScope:phone3==phone4=>{isflg2}");bool isflg3 = object.ReferenceEquals(phone1, phone3);Console.WriteLine($"InstancePerLifetimeScope:phone1==phone3=>{isflg3}"); } IPhone phone5 = null; IPhone phone6 = null; using (var scope = container.BeginLifetimeScope()) {phone5 = scope.Resolve<IPhone>();phone6 = scope.Resolve<IPhone>();bool isflg2 = object.ReferenceEquals(phone5, phone6);Console.WriteLine($"InstancePerLifetimeScope:phone5==phone6=>{isflg2}");bool isflg3 = object.ReferenceEquals(phone1, phone5);Console.WriteLine($"InstancePerLifetimeScope:phone1==phone5=>{isflg3}"); } bool isflg4 = object.ReferenceEquals(phone3, phone5); Console.WriteLine($"InstancePerLifetimeScope:phone3==phone5=>{isflg4}"); InstancePerLifetimeScope:phone1==phone2=>True InstancePerLifetimeScope:phone3==phone4=>True InstancePerLifetimeScope:phone1==phone3=>False InstancePerLifetimeScope:phone5==phone6=>True InstancePerLifetimeScope:phone1==phone5=>False InstancePerLifetimeScope:phone3==phone5=>False(4)作用域范圍生命周期
在作用域范圍外無法創(chuàng)建實(shí)例,在作用域范圍里面,同一個(gè)作用域下面的對(duì)象是同一個(gè),關(guān)鍵詞InstancePerMatchingLifetimeScope
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>().InstancePerMatchingLifetimeScope("scope1", "scope2"); IContainer container = containerBuilder.Build(); IPhone phone1 = null; IPhone phone2 = null; using (var scope = container.BeginLifetimeScope("scope1")) {phone1 = scope.Resolve<IPhone>();phone2 = scope.Resolve<IPhone>();bool isflg1 = object.ReferenceEquals(phone1, phone2);Console.WriteLine($"InstancePerMatchingLifetimeScope:phone1==phone2=>{isflg1}"); } IPhone phone3 = null; using (var scope = container.BeginLifetimeScope("scope2")) {phone3 = scope.Resolve<IPhone>(); } IPhone phone4 = null; using (var scope = container.BeginLifetimeScope("scope2")) { phone4 = scope.Resolve<IPhone>(); } bool isflg2 = object.ReferenceEquals(phone3, phone4); Console.WriteLine($"InstancePerMatchingLifetimeScope:phone3==phone4=>{isflg2}"); bool isflg3 = object.ReferenceEquals(phone1, phone3); Console.WriteLine($"InstancePerMatchingLifetimeScope:phone1==phone3=>{isflg3}"); InstancePerMatchingLifetimeScope:phone1==phone2=>True InstancePerMatchingLifetimeScope:phone3==phone4=>False InstancePerMatchingLifetimeScope:phone1==phone3=>False(5)一次請(qǐng)求同一個(gè)對(duì)象
關(guān)鍵詞InstancePerRequest,只能在web項(xiàng)目中調(diào)試,控制臺(tái)報(bào)錯(cuò)
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>().InstancePerRequest(); IContainer container = containerBuilder.Build(); IPhone phone1 = container.Resolve<IPhone>(); IPhone phone2 = container.Resolve<IPhone>(); bool isflg1 = object.ReferenceEquals(phone1, phone2); Console.WriteLine($"InstancePerRequest:phone1==phone2=>{isflg1}");6、支持配置文件注冊(cè)
(1)nuget引入程序集
Autofac Autofac.Configuration Microsoft.Extensions.Configuration.Json(2)配置文件autofac.json,屬性->始終復(fù)制
{"components": [{//實(shí)現(xiàn)"type": "Net5.IOC.Honer,Net5.IOC",//抽象"services": [{"type": "Net5.IOC.IPhone,Net5.IOC"}],//生命周期"instanceScope": "single-instance",//屬性注入 "injectProperties": true}] }(3)通過配置文件注冊(cè)創(chuàng)建對(duì)象
ContainerBuilder containerBuilder = new ContainerBuilder(); IConfigurationBuilder config = new ConfigurationBuilder(); IConfigurationSource autofacJsonConfigSource = new JsonConfigurationSource() {Path = "Autofac/autofac.json",Optional = false,//boolean,默認(rèn)就是false,可不寫ReloadOnChange = true,//同上 }; config.Add(autofacJsonConfigSource); ConfigurationModule module = new ConfigurationModule(config.Build()); containerBuilder.RegisterModule(module); IContainer container = containerBuilder.Build(); IPhone phone1 = container.Resolve<IPhone>(); IPhone phone2 = container.Resolve<IPhone>(); bool isflg1 = object.ReferenceEquals(phone1, phone2); Console.WriteLine($"配置文件注冊(cè):phone1==phone2=>{isflg1}");(4)運(yùn)行結(jié)果
配置文件注冊(cè):phone1==phone2=>True7、支持AOP切面編程
可以在不修改方法的前提下,在方法前后添加公共邏輯,日志,異常,緩存等
(1)nuget引入程序集
Castle.Core Autofac.Extras.DynamicProxy(2)自定義一個(gè)切面類實(shí)現(xiàn)IInterceptor接口
public class CustomInterceptor : IInterceptor {public void Intercept(IInvocation invocation){Console.WriteLine("方法執(zhí)行前。。。");//執(zhí)行當(dāng)前方法invocation.Proceed();Console.WriteLine("方法執(zhí)行后。。。");} }(3)在抽象/實(shí)現(xiàn)類上添加特性標(biāo)記
[Intercept(typeof(CustomInterceptor))] public interface IPhone {string ShowName(); } //實(shí)現(xiàn)類虛方法 public class Honer : IPhone {public virtual string ShowName(){Console.WriteLine("Honer");return "Honer";} }(4)在容器中注冊(cè)關(guān)系創(chuàng)建對(duì)象
- EnableInterfaceInterceptors + 特性標(biāo)記在抽象上,所有實(shí)現(xiàn)類都支持AOP
- EnableInterfaceInterceptors + 特性標(biāo)記到實(shí)現(xiàn)類上,標(biāo)記的類就支持AOP
- EnableClassInterceptors,要支持AOP的方法必須要是用virtual虛方法
- EnableClassInterceptors + 特性標(biāo)記在抽象上,所有實(shí)現(xiàn)類都支持AOP
- EnableClassInterceptors + 特性標(biāo)記到實(shí)現(xiàn)類上,標(biāo)記的類就支持AOP
(5)運(yùn)行結(jié)果
方法執(zhí)行前。。。 Honer 方法執(zhí)行后。。。8、單抽象多實(shí)現(xiàn)問題
(1)在容器中注冊(cè)關(guān)系創(chuàng)建對(duì)象
注冊(cè)的時(shí)候不標(biāo)記名字,后注冊(cè)的會(huì)覆蓋先注冊(cè)的
注冊(cè)的時(shí)候標(biāo)記下名字,創(chuàng)建對(duì)象的時(shí)候用名稱來區(qū)分
(2)運(yùn)行結(jié)果
Honer Huawei9、集成到Asp.NetCore5框架
(1)nuget引入程序集
Autofac Autofac.Extensions.DependencyInjection(2)定義實(shí)現(xiàn)類和抽象
public class UserService : IUserService { private IUserRepository UserRepositoryCtor { get; set; }public UserService(IUserRepository userRepository){UserRepositoryCtor = userRepository;} public string Login(string username, string password){return "登錄成功";} }(3)添加控制器和頁(yè)面
public class FourthController : Controller {private IUserService _userService;public FourthController(IUserService userService){this._userService = userService;}public IActionResult Index(){object result = this._userService.Login("username", "password");return View(result);} } @model String <h2>this is fourth index...</h2> <h2>@Model</h2>(4)在Program替換容器工廠
public class Program {public static void Main(string[] args){CreateHostBuilder(args).Build().Run();}public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>();}).UseServiceProviderFactory(new AutofacServiceProviderFactory()); }(5)在Startup類的ConfigureServices方法中替換創(chuàng)建控制器的類
//控制器默認(rèn)是有IControllerActivator創(chuàng)建的,替換成由容器創(chuàng)建 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());(6)注冊(cè)抽象和實(shí)現(xiàn)的關(guān)系
在Startup類中專門增加一個(gè)方法ConfigureContainer,用于注冊(cè)抽象和實(shí)現(xiàn),可以把這些注冊(cè)信息進(jìn)行模塊化封裝到AutofacModule
當(dāng)抽象類和實(shí)現(xiàn)非常多的時(shí)候,可以將整個(gè)dll注冊(cè),特殊的關(guān)系可以寫在后面覆蓋前面的注冊(cè)關(guān)系。
/// <summary> /// Autofac專用:注冊(cè)抽象和細(xì)節(jié)之間的關(guān)系,使用autofac后原來內(nèi)置注冊(cè)的關(guān)系要注釋掉 /// Autofac和ServiceCollection是二者并存的,Autofac會(huì)接管ServiceCollection的一切 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) {builder.RegisterModule<AutofacModule>(); } public class AutofacModule : Module {/// <summary>/// 重寫Autofac管道中的Load方法,在這里注入注冊(cè)的內(nèi)容/// </summary>/// <param name="builder"></param>protected override void Load(ContainerBuilder builder){//注冊(cè)抽象與實(shí)現(xiàn)builder.RegisterType<UserRepository>().As<IUserRepository>();builder.RegisterType<UserService>().As<IUserService>();//注冊(cè)所有控制器類var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();//實(shí)現(xiàn)屬性注入,這邊無法實(shí)現(xiàn)方法注入builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();} }(7)運(yùn)行結(jié)果
(8)在Startup的Configure方法中用容器創(chuàng)建對(duì)象
using (var container = host.Services.CreateScope()) {IUserService userService = container.ServiceProvider.GetService<IUserService>(); }(9)單抽象多實(shí)現(xiàn)集成到框架
注入的時(shí)候通過構(gòu)造函數(shù)或者屬性注入autofac上下文實(shí)例,再根據(jù)名稱創(chuàng)建對(duì)應(yīng)實(shí)例。
定義單抽象和多實(shí)例類
//抽象 public interface ITestService {string Show(); } //實(shí)現(xiàn)1 public class TestServiceA : ITestService {public string Show(){return "TestServiceA";} } //實(shí)現(xiàn)2 public class TestServiceB : ITestService {public string Show(){return "TestServiceB";} }在AutofacModule注冊(cè)抽象和實(shí)現(xiàn)的關(guān)系
//單抽象多實(shí)現(xiàn)注冊(cè) builder.RegisterType<TestServiceA>().Named<ITestService>("a"); builder.RegisterType<TestServiceB>().Named<ITestService>("b");添加控制器和頁(yè)面
public class FifthController : Controller {private IComponentContext _componentContext;public FifthController(IComponentContext componentContext){this._componentContext = componentContext;}public IActionResult Index(){ITestService testServiceA = _componentContext.ResolveNamed<ITestService>("a");ITestService testServiceB = _componentContext.ResolveNamed<ITestService>("b");object result = $"{testServiceA.Show()}--{testServiceB.Show()}";return View(result);} } @model String <h2>this is Fifth index...</h2> <h2>@Model</h2>運(yùn)行結(jié)果
總結(jié)
- 上一篇: 编程探究智能手机的图案解锁
- 下一篇: 水利工程资料管理软件