IOC(inversion of control)控制反转
以前我们把框架分为三层架构:UI层,BLL层,DAL层。在三层架构中我们,我们是一层一层的调用对象里面的方法,需要实例化对象:类名 对象名 = new 类名();这种叫传统工艺。
现在我们不需要在依赖某一个类来获取到实例。而是依赖于抽象,怎么获取?交给了第三方(称:IOC容器)通过抽象(接口,抽象类,普通父类)的方式获取到类的实例。
IOC内置容器:ServiceCollection
1.创建库类接口【Interfaces】里面什么都不写,只是做依赖注入的关系
public interface IMicrophone{ }
2.创建一个服务类库【Services】做我们需要调用的具体对象
public class Microphone: IMicrophone { public Microphone() { Console.WriteLine($"{this.GetType().Name}被构造了"); } }
3.通过容器依赖注入到项目中来
using Interfaces;//接口类库 using Services;//服务类库 using Microsoft.Extensions.DependencyInjection;//内置IOC容器 ServiceCollection service = new ServiceCollection();//1.创建一个容器,需要nuget引入:Microsoft.Extensions.DependencyInjection service.AddTransient<IMicrophone, Microphone>();//2.建立关系或是注册抽象和具体普通类之间的关系,注册方式有很多,这里只是其中一种 ServiceProvider sp = service.BuildServiceProvider();//3.进行集中管理,统一注入到ServiceProvider,而BuildServiceProvider就是获取依赖关系 IMicrophone microphone= sp.GetService<IMicrophone>();//4.获取抽象的具体实例,就相当于Microphone被实例化后的具体对象,通过接口抽象出来的
传统工艺:new 实例化对象。对象创建在项目中是多个地方的。
ioc容器可以在全局,配置抽象和具体普通类之间的关系,是可以修改AddTransient<抽象, 具体类>();修改为什么获取的就是什么。
ioc容器,最大的好处在于DI依赖注入:如果A依赖于B,B依赖于C;那么在创建A时,会把C先创建出来交给B,在把B创建出来交给A,从而创建出A对象来。
public interface IHeadphone{ }//接口 public class Headphone : IHeadphone //依赖于IPower { public Headphone(IPower power) { Console.WriteLine($"{this.GetType().Name}被构造了"); } }
Power依赖于IMicrophone
public interface IPower { } //接口 public class Power : IPower { public Power(IMicrophone microphone) { Console.WriteLine($"{this.GetType().Name}被构造了"); } }
Microphone有继承了IMicrophone
public interface IMicrophone{ }//接口 public class Microphone: IMicrophone { public Microphone() { Console.WriteLine($"{this.GetType().Name}被构造了"); } }
这种依赖注入关系叫构造函数注入
using Interfaces;//接口类库 using Services;//服务类库 using Microsoft.Extensions.DependencyInjection;//内置IOC容器 Console.WriteLine("传统工艺,实例化对象-------------------"); IMicrophone m =new Microphone(); IPower p = new Power(m); IHeadphone h = new Headphone(p); Console.WriteLine("IOC容器支持的依赖注入-----------------------"); ServiceCollection service = new ServiceCollection();//1.创建容器:ioc容器本质就是个工厂用来创建对象的 service.AddTransient<IMicrophone, Microphone>();//2.建立关系 service.AddTransient<IPower, Power>(); service.AddTransient<IHeadphone, Headphone>(); ServiceProvider sp = service.BuildServiceProvider();//3.进行集中管理,获取依赖关系 IHeadphone headphone = sp.GetService<IHeadphone>();//4.获取实例
依赖注入有三种【1.构造函数注入;2.方法注入;3.属性注入】但内置ioc容器只支持构造函数注入,其他两种只能去扩展
ServiceCollection的生命周期
ServiceCollection service = new ServiceCollection(); service.AddTransient<IMicrophone, Microphone>();//Transient:瞬时生命周期,每一次创建都是新的实例 service.AddSingleton<IHeadphone, Headphone>();//Singleton:单例的生命周期,相同的一个引用地址,同一对象实例 service.AddScoped<IPower, Power>();//Scoped:作用域生命周期,保存在相同的ServiceProvider对象里,获取是相同的实例,反之不同 ServiceProvider sp = service.BuildServiceProvider();//获取依赖关系保存到对象 IMicrophone m1 = sp.GetService<IMicrophone>(); IMicrophone m2 = sp.GetService<IMicrophone>(); Console.WriteLine($"Transient:瞬时生命周期比较m1和m2是否一样:{object.ReferenceEquals(m1,m2)}"); IHeadphone h1 = sp.GetService<IHeadphone>(); IHeadphone h2 = sp.GetService<IHeadphone>(); Console.WriteLine($"Singleton:单例生命周期比较h1和h2是否一样:{object.ReferenceEquals(h1, h2)}"); IPower p1 = sp.GetService<IPower>(); IPower p2 = sp.GetService<IPower>(); Console.WriteLine($"Scoped:作用域生命周期比较p1和p2是否一样:{object.ReferenceEquals(p1, p2)}");
ServiceCollection的多种注册:上面使用的是泛型注册
ServiceCollection service = new ServiceCollection(); service.AddTransient(typeof(IMicrophone), typeof(Microphone));//方法注册和泛型注册一样的 service.AddTransient(typeof(Microphone));//可以直接给个具体实例,调用也是实例 service.AddTransient<Microphone>();//泛型注册,也可以直接给一个实例 service.AddTransient(typeof(IPower), a => { //委托,注册抽象和一段业务逻辑 //在这里我们可以直接来决定创建这个对象的实例,可以对这个实例做加工。 IMicrophone m = a.GetService<IMicrophone>(); return new Power(m); }); ServiceProvider sp = service.BuildServiceProvider(); IMicrophone m1 = sp.GetService<IMicrophone>(); Microphone m2 = sp.GetService<Microphone>();//泛型注册也是一样的,可以直接给一个实例 IPower p = sp.GetService<IPower>();
ServiceCollection容器在asp.net core中的使用:首先在【Program.cs】
builder.Services.AddTransient<IMicrophone, Microphone>();//依赖:在顶级程序中注册内置ioc容器。
注入:到控制器(构造方法)中注入使用
private readonly IMicrophone microphone;public HomeController(IMicrophone microphone, IServiceProvider sp)//home控制器的构造方法 { this.microphone = microphone;//方法1:注入进来的ioc容器 this.microphone = sp.GetService<IMicrophone>();//方法2::这两种获取方式是一样 }
Autofac
新的容器替代内置容器,需要引入: