Autofac详解
Autofac詳解
零、文章目錄
一、Autofac詳解
1、概述
- Autofac是第三方IOC容器,是當前最流行的IOC容器。
- 功能強大,比asp.netcore內置容器強大得多,支持屬性注入和方法注入,支持AOP。
- 官網地址:http://autofac.org/
- 源碼下載地址:https://github.com/autofac/Autofac
2、快速開始
(1)Nuget引入程序包
Autofac 基于版本6.3演示,Net5(2)容器創建對象
//創建一個容器建造者 ContainerBuilder containerBuilder = new ContainerBuilder(); //注冊普通類 containerBuilder.RegisterType<Honer>(); //build一下,得到一個容器 IContainer container = containerBuilder.Build(); //可以基于容器來獲取對象的實例 Honer phone = container.Resolve<Honer>();3、注冊的類型
(1)注冊普通類
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>(); IContainer container = containerBuilder.Build(); Honer phone = container.Resolve<Honer>();(2)注冊抽象與實現
ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); IContainer container = containerBuilder.Build(); IPhone phone = container.Resolve<IPhone>();(3)注冊程序集
- RegisterAssemblyTypes(程序集數組),程序集必須是public的
- AsImplementedInterfaces():表示注冊的類型,以接口的方式注冊
- PropertiesAutowired():支持屬性注入
- Where:滿足條件類型注冊
4、三種注入方式
(1)構造函數注入
默認支持,無法用特性進行篩選,默認選參數最多的構造函數進行注入
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)全部屬性注入
關鍵詞PropertiesAutowired,這個對象所有屬性全部注入
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)標記特性的屬性注入
關鍵詞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)方法注入
關鍵詞OnActivated,指定調用方法
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、對象生命周期
(1)瞬時生命周期
每次獲取都是全新的實例,關鍵詞InstancePerDependency,默認的生命周期
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)單例生命周期
同一個進程內都是同一個實例,關鍵詞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)作用域生命周期
同一個作用域內都是同一個實例,關鍵詞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)作用域范圍生命周期
在作用域范圍外無法創建實例,在作用域范圍里面,同一個作用域下面的對象是同一個,關鍵詞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)一次請求同一個對象
關鍵詞InstancePerRequest,只能在web項目中調試,控制臺報錯
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、支持配置文件注冊
(1)nuget引入程序集
Autofac Autofac.Configuration Microsoft.Extensions.Configuration.Json(2)配置文件autofac.json,屬性->始終復制
{"components": [{//實現"type": "Net5.IOC.Honer,Net5.IOC",//抽象"services": [{"type": "Net5.IOC.IPhone,Net5.IOC"}],//生命周期"instanceScope": "single-instance",//屬性注入 "injectProperties": true}] }(3)通過配置文件注冊創建對象
ContainerBuilder containerBuilder = new ContainerBuilder(); IConfigurationBuilder config = new ConfigurationBuilder(); IConfigurationSource autofacJsonConfigSource = new JsonConfigurationSource() {Path = "Autofac/autofac.json",Optional = false,//boolean,默認就是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($"配置文件注冊:phone1==phone2=>{isflg1}");(4)運行結果
配置文件注冊:phone1==phone2=>True7、支持AOP切面編程
可以在不修改方法的前提下,在方法前后添加公共邏輯,日志,異常,緩存等
(1)nuget引入程序集
Castle.Core Autofac.Extras.DynamicProxy(2)自定義一個切面類實現IInterceptor接口
public class CustomInterceptor : IInterceptor {public void Intercept(IInvocation invocation){Console.WriteLine("方法執行前。。。");//執行當前方法invocation.Proceed();Console.WriteLine("方法執行后。。。");} }(3)在抽象/實現類上添加特性標記
[Intercept(typeof(CustomInterceptor))] public interface IPhone {string ShowName(); } //實現類虛方法 public class Honer : IPhone {public virtual string ShowName(){Console.WriteLine("Honer");return "Honer";} }(4)在容器中注冊關系創建對象
- EnableInterfaceInterceptors + 特性標記在抽象上,所有實現類都支持AOP
- EnableInterfaceInterceptors + 特性標記到實現類上,標記的類就支持AOP
- EnableClassInterceptors,要支持AOP的方法必須要是用virtual虛方法
- EnableClassInterceptors + 特性標記在抽象上,所有實現類都支持AOP
- EnableClassInterceptors + 特性標記到實現類上,標記的類就支持AOP
(5)運行結果
方法執行前。。。 Honer 方法執行后。。。8、單抽象多實現問題
(1)在容器中注冊關系創建對象
注冊的時候不標記名字,后注冊的會覆蓋先注冊的
注冊的時候標記下名字,創建對象的時候用名稱來區分
(2)運行結果
Honer Huawei9、集成到Asp.NetCore5框架
(1)nuget引入程序集
Autofac Autofac.Extensions.DependencyInjection(2)定義實現類和抽象
public class UserService : IUserService { private IUserRepository UserRepositoryCtor { get; set; }public UserService(IUserRepository userRepository){UserRepositoryCtor = userRepository;} public string Login(string username, string password){return "登錄成功";} }(3)添加控制器和頁面
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方法中替換創建控制器的類
//控制器默認是有IControllerActivator創建的,替換成由容器創建 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());(6)注冊抽象和實現的關系
在Startup類中專門增加一個方法ConfigureContainer,用于注冊抽象和實現,可以把這些注冊信息進行模塊化封裝到AutofacModule
當抽象類和實現非常多的時候,可以將整個dll注冊,特殊的關系可以寫在后面覆蓋前面的注冊關系。
/// <summary> /// Autofac專用:注冊抽象和細節之間的關系,使用autofac后原來內置注冊的關系要注釋掉 /// Autofac和ServiceCollection是二者并存的,Autofac會接管ServiceCollection的一切 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) {builder.RegisterModule<AutofacModule>(); } public class AutofacModule : Module {/// <summary>/// 重寫Autofac管道中的Load方法,在這里注入注冊的內容/// </summary>/// <param name="builder"></param>protected override void Load(ContainerBuilder builder){//注冊抽象與實現builder.RegisterType<UserRepository>().As<IUserRepository>();builder.RegisterType<UserService>().As<IUserService>();//注冊所有控制器類var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();//實現屬性注入,這邊無法實現方法注入builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();} }(7)運行結果
(8)在Startup的Configure方法中用容器創建對象
using (var container = host.Services.CreateScope()) {IUserService userService = container.ServiceProvider.GetService<IUserService>(); }(9)單抽象多實現集成到框架
注入的時候通過構造函數或者屬性注入autofac上下文實例,再根據名稱創建對應實例。
定義單抽象和多實例類
//抽象 public interface ITestService {string Show(); } //實現1 public class TestServiceA : ITestService {public string Show(){return "TestServiceA";} } //實現2 public class TestServiceB : ITestService {public string Show(){return "TestServiceB";} }在AutofacModule注冊抽象和實現的關系
//單抽象多實現注冊 builder.RegisterType<TestServiceA>().Named<ITestService>("a"); builder.RegisterType<TestServiceB>().Named<ITestService>("b");添加控制器和頁面
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>運行結果
總結
- 上一篇: 编程探究智能手机的图案解锁
- 下一篇: 水利工程资料管理软件