ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjection),所以能够完全兼容.net Core中的依赖注入的用法,同时使用 Autofac 替换了.net Core中的内部容器,利用了Autofac中的一些特性。
Abp依赖注入的配置方式
手动注册依赖注入关系
Startup类中的ConfigureServices()
方法中,通过IServiceCollection
向容器中添加依赖注入关系没有区别,在Abp框架中也完成兼容这种方式。
[DependsOn(typeof(AbpAspNetCoreModule))]
[DependsOn(typeof(SuncereAbpDataModule))]
public class SuncereAbpFreeSqlModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddFreeSql();
}
}
示例中的代码是我们项目中一个ORM模块的依赖注入配置,这是模块基于FreeSql这个ORM框架进行了一层分组,兼容了Abp的工作单元、默认仓储模式。上一篇文章中讲在Abp框架初始化时,会将容器对象在各个模块类中进行传递,context.Services
就是传递过来的IServiceCollection
。
按照约定自动注册
• ITransientDependency 注册为transient生命周期.
• ISingletonDependency 注册为singleton生命周期.
• IScopedDependency 注册为scoped生命周期.
这些接口,都是空接口,起到标记的作用。这种设计方式,在微软的代码和很多框架中都很常见。
查看自动依赖注入源码的入口点,其实就在上篇文章中提到的Abp引擎初始化过程中,AbpApplicationBase
构造函数中调用的AddCoreAbpServices()
方法中,其中的services.AddAssemblyOf<IAbpApplication>()
是关键。
DefaultConventionalRegistrar、ConventionalRegistrarBase
、ExposedServiceExplorer
、ExposeServicesAttribute
代码的查看,可以明白Abp默认的依赖关系注册是怎么样的,以及它是怎么实现的。
默认规则注册:
1)实现了ITransientDependency等三个接口的公开、非泛型类,会被注册到容器中。
2)如果这个类实现了其他接口,并且这个接口和类之间的命名符合规则,接口和类的关系会被注册到容器中。
例如
public class BookRepository: IRepository, IBookRepository, IBookStore, ITransientDependency
{
}
上面的代码中,BookRepository
在容器中是可以找到三个依赖关系配置的。
AbpAspNetCoreMvcConventionalRegistrar、Volo.Abp.AspNetCore.Components
中的AbpWebAssemblyConventionalRegistrar
等。
Abp框架固有的注册类型
一些特定类型会默认注册到依赖注入.例子:
• 模块类注册为singleton.
• MVC控制器(继承Controller或AbpController)被注册为transient.
• MVC页面模型(继承PageModel或AbpPageModel)被注册为transient.
• MVC视图组件(继承ViewComponent或AbpViewComponent)被注册为transient.
• 应用程序服务(实现IApplicationService接口或继承ApplicationService类)注册为transient.
• 存储库(实现IRepository接口)注册为transient.
• 域服务(实现IDomainService接口)注册为transient.
我们也可以通过实现自己的依赖注入注册规则,只需要实现IConventionalRegistrar
接口,并在模块类中的PreConfigureServices()
方法中将其添加到ConventionalRegistrarList
中。
通过特性注册
我们可以用 DependencyAttribute
声明依赖注入的生命周期和注入的方式,ExposeServicesAttribute
声明类和接口之间的对应关系。ExposeServicesAttribute
就是 IExposedServiceTypesProvider
的实现类。
ExposeServicesAttribute,并且未设置IncludeDefaults
、IncludeSelf
的值的情况下,由于默认值的关系,这两个值会是false,即默认约定不起作用了,该类注册为ExposeServicesAttribute
中指定的接口的实现。 当然ExposeServicesAttribute
可以指定多个接口。
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IBookRepository))]
public class BookRepository: IRepository, IBookRepository, IBookStore
{
}
泛型类的注册
通过源码可以知道,无论是按照约定自动注册,还是通过特性的方式进行注册,都是无法注册泛型类的依赖注入关系的,泛型类的依赖注入关系只能够通过手动注册的方式注入。
context.service.AddTransient<IRepository<,>, Repository<,>>();
通过以上方式可以注册泛型类的依赖注入关系,<> 中一个,表示该类有两个泛型类型。
ABP 系列总结:
上一篇:ABP - 模块加载机制