.Net Core 依赖注入
为什么要使用依赖注入框架.Net Core DI核心类三种生命周期服务注册单例注册作用域注册瞬时注册直接注入实例工厂模式注册注册不同实例尝试注册移除和替换注册注册泛型模板使用依赖注入注意点实现 IDisposable 接口类型的释放Autofac基于名称的注入属性注入子容器基于动态代理的 AOP
.Net Core 依赖注入
为什么要使用依赖注入框架
- 借助依赖注入框架,将对象的创建交由容器管理,确保代码的可维护性和可扩展性。
- .NET Core 的整个架构中,依赖注入框架提供了对象创建和生命周期管理的核心能力,各个组件相互协作,也是由依赖注入框架的能力来实现的。
.Net Core DI
.Net Core实现依赖注入两个包:
Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection.Abstractions 为抽象包,Microsoft.Extensions.DependencyInjection 为具体实现包
核心类
IServiceCollection
ServiceDescriptor
IServiceProvider
IServiceScope
IServiceCollection 负责注册,作为Startup类中ConfigureServices方法的参数,使用其对对象进行注册。
ServiceDescriptor 负责注入服务元素的描述
IServiceProvider 负责提供实例
IServiceScope 负责实例的生命周期
三种生命周期
- 瞬时 Transient:每次请求,都获取一个新的实例;即使同一个请求获取多次也会是不同的实例。
- 作用域 Scoped: 每次请求,都获取一个新的实例;同一个请求获取多次会得到相同的实例,即一个http请求内唯一。
- 单例 Singleton:每次都获取同一个实例。
服务注册
单例注册
services.AddSingleton<IMyService, MyService>();
作用域注册
services.AddScoped<IMyService, MyService>();
瞬时注册
services.AddTransient<IMyService, MyService>();
直接注入实例
services.AddScoped<IMyService>(new MyService());
工厂模式注册
services.AddScoped<IMyService>(serviceProvider =>
{
return new MyService();
});
注册不同实例
services.AddScoped<IMyService>(new MyService());
services.AddScoped<IMyService>(new MyService2());
MyService和MyService2均实现了IMyService接口,并且进行了注册;使用的时候,默认是用的最后注册的(MyService2);如果要使用MyService, 需要遍历,根据实际类型来判断。
[HttpGet]
public async Tash GetServiceList([FromServices] IEnumerable<IMyService> services)
{
foreach (var service in services)
{
if (service is MyService) // if (service.GetType() == typeof(MyService))
{
// do sth
}
}
}
尝试注册
services.TryAddScoped<IMyService>(new MyService());
services.TryAddEnumerable(ServiceDescriptor.Scoped<IMyService, MyService>());
尝试注册会先判断实例是否已经注册,若注册了则不再进行注册;尝试注册可以有效的避免服务重复注册。
移除和替换注册
services.AddScoped<IMyService, MyService>();
services.Replace(ServiceDescriptor.Singleton<IMyService, MyService2>());
services.RemoveAll<IMyService>();
替换注册可以替换原有实例注册MyService为MyService2,RemoveAll则是移除所以实现了IMyService的注册实例。
注册泛型模板
services.AddScoped(typeof(IGenericService<>), typeof(GenericService<>));
使用依赖注入注意点
- 避免通过静态属性的方式访问容器对象
- 避免在服务内部使用 GetService 方式来获取实例
- 避免使用静态属性存储单例,应该使用容器管理单例对象
- 避免在服务中实例化依赖对象,应该使用依赖注入来获得依赖对象
- 避免向单例的类型注入范围的类型
实现 IDisposable 接口类型的释放
- DI 只负责释放由其创建的对象实例
- DI 在容器或子容器释放时,释放由其创建的对象实例
- 避免手动创建实现了 IDisposable 对象,应该使用容器来管理其生命周期
Autofac
Autofac的功能比.Net Core 的原生依赖注入更丰富,具体表现在:
- 基于名称的注入
- 属性注入
- 子容器
- 基于动态代理的 AOP
基于名称的注入
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterType<MyService>().Named<IMyService>("s1");
builder.RegisterType<MyService2>().Named<IMyService>("s1");
}
从IoC容器中使用ResolveNamed获取:
var s1 = container.ResolveNamed<IMyService>("s1");
var s2 = container.ResolveNamed<IMyService>("s2");
属性注入
使用PropertiesAutowired方法支持属性注入:
builder.RegisterType<MyService>().As<IMyService>().PropertiesAutowired();
子容器
builder.RegisterType<MyService>().InstancePerMatchingLifetimeScope("myscope");
使用
var autofacContainer = app.ApplicationServices.GetAutofacRoot();
using (var myscope = autofacContainer.BeginLifetimeScope("myscope"))
{
var service1 = myscope.Resolve<MyService>();
using (var scope = myscope.BeginLifetimeScope())
{
var service2 = scope.Resolve<MyService>();
Console.WriteLine($"service1=service2:{service1 == service2}");
}
}
基于动态代理的 AOP
需要引用包:Autofac.Extras.DynamicProxy
先实现一个拦截器继承 IInterceptor
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Intercept before,Method:{invocation.Method.Name}");
invocation.Proceed();
Console.WriteLine($"Intercept after,Method:{invocation.Method.Name}");
}
}
注册
builder.RegisterType<MyService>().As<IMyService>().PropertiesAutowired().InterceptedBy(typeof(MyInterceptor)).EnableInterfaceInterceptors();
这里实现了基于接口的拦截,也可以实现基于类的拦截;基于类的拦截时,方法需要定义为虚方法。
更多推荐
所有评论(0)