ABP - 依赖注入(2)
依赖注入的使用
构造方法注入
这是将服务注入类的最常用方法,是将依赖项注入类的首选方式,也是微软推崇的模式。这样,除非提供了所有构造方法注入的依赖项,否则无法构造类,显示的声明了类必需的服务,使开发人员一目了然。
public class BookAppService : ApplicationService
{
private readonly IBookRepository _bookRepository;
public TaxAppService(IBookRepository bookRepository)
{
_bookRepository = bookRepository;
}
public void DoSomething()
{
//...使用 _bookRepository...
}
}
属性注入
Microsoft依赖注入库不支持属性注入, 属性注入是Abp框架使用autofac容器替换了微软默认的容器之后才能使用的,属于autofac的特性。
public class BookAppService : ITransientDependency
{
public ILogger<BookAppService> Logger { get; set; }
public BookAppService()
{
Logger = NullLogger<BookAppService>.Instance;
}
public void DoSomething()
{
//...使用 Logger 写日志...
}
}
属性注入依赖项通常被视为可选依赖项.这意味着不是必须的,没有它们服务也可以正常工作.Logger就是这样的依赖项,BookAppService可以继续工作而无需日志记录。为了使依赖项成为可选的,我们通常会为依赖项设置默认值。一般是接口的一个空实现,内部不做任何操作。
属性注入的一个限制是你不能在构造函数中使用依赖项,因为它是在对象构造之后设置的.
从IServiceProvider解析服务
public class MyService : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void DoSomething()
{
using (var scope = _serviceProvider.CreateScope())
{
var service1 = scope.ServiceProvider.GetService<IMyService1>();
// …
}
}
}
通过GetService、GetRequiredService可以直接从容器中解析出我们需要的服务,这两个方法有一定的区别,推荐使用GetRequiredService方法。
这种情况下一般会使用using (var scope = _serviceProvider.CreateScope()){} 创建一个域,以便解析出来的服务能够安全的被释放,这也能够减少一些内存消耗。
要注意的一个点是,在以前的ASP.NET Boilerplate 中服务的手动解析使用是通过IocManager的,这是静态类,通过IocManager.Instance可以获得容器对象,很方便使用。但是在现在的ABP中已经将这种方式移除了,以至于有时候在静态类中需要使用一些服务的时候很不方便(虽然这种方式不是很正确,但是确实有时候会有这样子的需求)。
所以在项目中如果真的有需要的话,可以自己构建一个类似于IocManager的方式,但是不推荐这样子用,因为在某些情况确实会存在一些问题,导致一些资源和生命周期的冲突,特别是在单元测试之中。
/// <summary>
/// ServiceManager构建一个单例,用于寄放IServiceProvider
/// 使用此类时,需要在应用启动的时候,调用Init方法
/// 一般情况下不推荐使用
/// </summary>
public class ServiceManager
{
private ServiceManager()
{
}
public static IServiceProvider ServiceProvider { get; private set; }
public static void Init(IServiceProvider service)
{
ServiceProvider = service;
}
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
// 保存全局Ioc
if (app != null)
{
ServiceManager.Init(app.ApplicationServices);
}
}
Autofac的使用
容器替换
Abp框架中使用autofac依赖注入框架替换了微软默认的容器,在volo.abp.autofac模块中按照模块化设计的思想进行了稍微的封装,提供了便捷的替换方式。
使用autofac替换默认容器的方式:
(1) 在startup类中的ConfigureServices()中,在添加Abp的依赖注入时,通过选项替换。
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddApplication<MyWebModule>(options =>
{
//Integrate Autofac!
options.UseAutofac();
});
return services.BuildServiceProviderFromFactory();
}
(2) 在program.cs中,在.net Core 主机(host)创建的时候,调用userAutofac()扩展方法。
internal static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac();
拦截器与动态代理
Abp框架使用autofac替换微软默认容器的目的,主要就是为了利用autofac的拦截器功能,这是一种动态aop的实现方式,可以动态的拦截往容器中注册的类,做一些想要的操作。abp框架中的很多横切关注点都是通过这种方式实现的,如权限认证,审计等。
在模块类的PreConfigureServices()中,可以使用OnRegistred()方法,注册一个回调,每次有类向容器中注册时,都会调用这个回调。在回调中,我们可以对当前注册的类型进行判断(一般通过接口、特性等),如果满足我们的条件,就添加一个拦截器。



在我们调用useAutofac()时,内部会调用UseServiceProviderFactory()创建了一个AbpAutofacServiceProviderFactory,这是实现了微软IServiceProviderFactory<>接口的一个容器工厂,任何容器提供了这个接口实现类,并且按照约定提供了ContainerBuilder,都可以作为.net core中的依赖注入容器。
在.net Core应用程序启动的时候会调用IServiceProviderFactory<>接口的CreateBuilder(IServiceCollection services)方法,我们注册的回调函数就是在这个时候执行的。遍历每一个类,在多个回调中进行执行,符合条件的都会添加一个拦截器。


最终是向autofac容器注册拦截器。
拦截器类需要实现IAbpInterceptor接口,或者继承AbpInterceptor,实现其中的InterceptAsync方法。如果对某一个类配置了拦截器,实际上它在注册到容器中时,abp会基于拦截器动态生成一个代理类,再将代理类注册到autofac中。
动态代理是基于Castle实现的。abp继承了Castle动态代理的AsyncDeterminationInterceptor,通过继承了AsyncInterceptorBase使用适配器模式将拦截器进行包装,并且将方法执行的参数进行封装传递到我们定义的拦截器中。


执行被拦截的类的方法时,实际上通过代理类在执行InterceptAsync()方法,这类似于传统过滤器的效果,所以通过这种方式,我们可以在方法执行前后添加一些和业务无关的全局的操作,即一些横切关注点。
ABP 系列总结:
目录:ABP 系列总结
上一篇:ABP - 依赖注入(1)
ABP - 依赖注入(2)的更多相关文章
- ABP(现代ASP.NET样板开发框架)系列之6、ABP依赖注入
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...
- 基于DDD的.NET开发框架 - ABP依赖注入
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- ABP依赖注入
ABP依赖注入 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.N ...
- 3. abp依赖注入的分析.md
abp依赖注入的原理剖析 请先移步参考 [Abp vNext 源码分析] - 3. 依赖注入与拦截器 本文此篇文章的补充和完善. abp的依赖注入最后是通过IConventionalRegister接 ...
- ABP 依赖注入
1.ABP自动注入 //IapplicationService注入方式暴露接 //ITransientDependency 不会暴露接口 ITransientDependency和ISingleton ...
- abp 依赖注入声明
public class SchedulerManager : ISingletonDependency { private ILogger logger; public SchedulerManag ...
- ABP框架 - 依赖注入
文档目录 本节内容: 什么是依赖注入 传统方式的问题 解决方案 构造器注入模式 属性注入模式 依赖注入框架 ABP 依赖注入基础 注册依赖 约定注入 辅助接口 自定义/直接 注册 使用IocManag ...
- (译)ABP之依赖注入
原文地址:https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection 什么是依赖注入 传统方式的问题 解决方案 构造函数注入 ...
- ABP官方文档翻译 2.1 依赖注入
依赖注入 什么是依赖注入 传统方式的问题 解决方案 构造函数注入模式 属性注入模式 依赖注入框架 ABP依赖注入基础设施 注册依赖注入 传统注册 帮助接口 自定义/直接注册 使用IocManager ...
- ASP.NET Core - 依赖注入(四)
4. ASP.NET Core默认服务 之前讲了中间件,实际上一个中间件要正常进行工作,通常需要许多的服务配合进行,而中间件中的服务自然也是通过 Ioc 容器进行注册和注入的.前面也讲到,按照约定中间 ...
随机推荐
- SpringBoot工程入门case
SpringBoot的设计目的是用来简化Spring应用的初始搭建以及开发过程. SpringBoot入门案例: 1.创建一个新module 2.除pom和src文件剩余都删除. 3.在src.com ...
- Flink基本概念及架构
1.基本概念 无界和有界数据.任何类型的数据都可以形成一种事件流.信用卡交易.传感器测量.机器日志.网站或移动应用程序上的用户交互记录,所有这些数据都形成一种流.数据可以被作为 无界 或者 有界 流来 ...
- spark中的持久化机制以及lineage和checkpoint(简含源码解析)
spark相比MapReduce最大的优势是,spark是基于内存的计算模型,有的spark应用比较复杂,如果中间出错了,那么只能根据lineage从头开始计算,所以为了避免这种情况,spark提供了 ...
- SpringBoot Windows 自启动 - 通过 Windows Service 服务实现
SpringBoot 在Windows运行时,有个黑窗体,容易被不小心选中或关闭,或者服务器重启后,不能自动运行,注册为 Windows Service服务 可实现 SpringBoot 项目在Win ...
- gulp基本操作
1.安装淘宝镜像 npm install cnpm -g --registry=https://registry.npm.taobao.org cnpm -v 2.生成项目描述文件 package.j ...
- QML和QT
推荐一些学习qml教程 Qt官方的QML教程: https://doc.qt.io/qt-5/qtqml-index.html,这是一个由Qt官方提供的完整的QML教程,包含了所有基本知识和高级语法. ...
- webrtc QOS笔记三 Nack机制浅析
nack源码浅析 nack源码浅析 Video Nack nack模块 nack list keyFrame list & recovered list nack 发送的策略 nack 模块的 ...
- pychearm日常用法
一 常用快捷键 编辑类:Ctrl + D 复制选定的区域或行Ctrl + Y 删除选定的行Ctrl + Alt + L 代码格式化Ctrl + Al ...
- w10通过修改注册表实现禁止更新系统
对于Windows系统更新或驱动更新,并不是越新越好,当然新版本的系统可能带来了许多新的功能.漏洞修补.漂亮的用户界面和流畅的系统优化等,但是新版本的系统和驱动更新有可能会造成CPU占用居高不下,文件 ...
- [SVN]SVN checkout 功能不可用 右键只看到提交和更新,没有显示checkout[转载]
不要在受SVN控制的文件夹里点右键,因为这个文件夹已经在SVN控制之下,当然不会允许在里面嵌套另一个SVN版本库 换个不受控的文件夹点右键,比如: D盘根目录 X 参考文献 SVN checkout ...