翼度科技»论坛 编程开发 .net 查看内容

ABP - 依赖注入(2)

9

主题

9

帖子

27

积分

新手上路

Rank: 1

积分
27
依赖注入的使用

构造方法注入

这是将服务注入类的最常用方法,是将依赖项注入类的首选方式,也是微软推崇的模式。这样,除非提供了所有构造方法注入的依赖项,否则无法构造类,显示的声明了类必需的服务,使开发人员一目了然。
  1. public class BookAppService : ApplicationService
  2. {
  3.     private readonly IBookRepository _bookRepository;
  4.                 public TaxAppService(IBookRepository bookRepository)
  5.     {
  6.         _bookRepository = bookRepository;
  7.     }
  8.                 public void DoSomething()
  9.     {
  10.         //...使用 _bookRepository...
  11.     }
  12. }
复制代码
属性注入

Microsoft依赖注入库不支持属性注入, 属性注入是Abp框架使用autofac容器替换了微软默认的容器之后才能使用的,属于autofac的特性。
  1. public class BookAppService : ITransientDependency
  2. {
  3.         public ILogger<BookAppService> Logger { get; set; }
  4.         public BookAppService()
  5.         {
  6.         Logger = NullLogger<BookAppService>.Instance;
  7.         }
  8.        
  9.         public void DoSomething()
  10.         {
  11.         //...使用 Logger 写日志...
  12.         }
  13. }
复制代码
属性注入依赖项通常被视为可选依赖项.这意味着不是必须的,没有它们服务也可以正常工作.Logger就是这样的依赖项,BookAppService可以继续工作而无需日志记录。为了使依赖项成为可选的,我们通常会为依赖项设置默认值。一般是接口的一个空实现,内部不做任何操作。
属性注入的一个限制是你不能在构造函数中使用依赖项,因为它是在对象构造之后设置的.
从IServiceProvider解析服务
  1. public class MyService : ITransientDependency
  2. {
  3.     private readonly IServiceProvider _serviceProvider;
  4.         public MyService(IServiceProvider serviceProvider)
  5.     {
  6.         _serviceProvider = serviceProvider;
  7.     }
  8.        
  9.         public void DoSomething()
  10.     {
  11.         
  12.                 using (var scope = _serviceProvider.CreateScope())
  13.                 {
  14.                         var service1 = scope.ServiceProvider.GetService<IMyService1>();
  15.                         // …
  16.                 }
  17.         }
  18. }
复制代码
通过GetService、GetRequiredService可以直接从容器中解析出我们需要的服务,这两个方法有一定的区别,推荐使用GetRequiredService方法。
这种情况下一般会使用using (var scope = _serviceProvider.CreateScope()){} 创建一个域,以便解析出来的服务能够安全的被释放,这也能够减少一些内存消耗。
要注意的一个点是,在以前的ASP.NET Boilerplate 中服务的手动解析使用是通过IocManager的,这是静态类,通过IocManager.Instance可以获得容器对象,很方便使用。但是在现在的ABP中已经将这种方式移除了,以至于有时候在静态类中需要使用一些服务的时候很不方便(虽然这种方式不是很正确,但是确实有时候会有这样子的需求)。
所以在项目中如果真的有需要的话,可以自己构建一个类似于IocManager的方式,但是不推荐这样子用,因为在某些情况确实会存在一些问题,导致一些资源和生命周期的冲突,特别是在单元测试之中。
  1. /// <summary>
  2. /// ServiceManager构建一个单例,用于寄放IServiceProvider
  3. /// 使用此类时,需要在应用启动的时候,调用Init方法
  4. /// 一般情况下不推荐使用
  5. /// </summary>
  6. public class ServiceManager
  7. {
  8.         private ServiceManager()
  9.         {
  10.         }
  11.         public static IServiceProvider ServiceProvider { get; private set; }
  12.         public static void Init(IServiceProvider service)
  13.         {
  14.                 ServiceProvider = service;
  15.         }
  16. }
复制代码
  1. public override void OnApplicationInitialization(ApplicationInitializationContext context)
  2. {
  3.         var app = context.GetApplicationBuilder();
  4.         // 保存全局Ioc
  5.         if (app != null)
  6.         {
  7.                 ServiceManager.Init(app.ApplicationServices);
  8.         }
  9. }
复制代码
Autofac的使用

容器替换

Abp框架中使用autofac依赖注入框架替换了微软默认的容器,在volo.abp.autofac模块中按照模块化设计的思想进行了稍微的封装,提供了便捷的替换方式。
使用autofac替换默认容器的方式:
(1) 在startup类中的ConfigureServices()中,在添加Abp的依赖注入时,通过选项替换。
  1. public IServiceProvider ConfigureServices(IServiceCollection services)
  2. {
  3.     services.AddApplication<MyWebModule>(options =>
  4.     {
  5.         //Integrate Autofac!
  6.         options.UseAutofac();
  7.     });
  8.     return services.BuildServiceProviderFromFactory();
  9. }
复制代码
(2) 在program.cs中,在.net Core 主机(host)创建的时候,调用userAutofac()扩展方法。
  1. internal static IHostBuilder CreateHostBuilder(string[] args) =>
  2.                     Host.CreateDefaultBuilder(args)
  3.                         .ConfigureWebHostDefaults(webBuilder =>
  4.                         {
  5.                             webBuilder.UseStartup<Startup>();
  6.                         })
  7.                 .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)

来源:https://www.cnblogs.com/wewant/archive/2023/05/30/17125223.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具