首页 > 其他分享 >ABP - 依赖注入(2)

ABP - 依赖注入(2)

时间:2023-05-30 14:11:48浏览次数:47  
标签:容器 autofac 拦截器 ABP 依赖 public 注入

依赖注入的使用

构造方法注入

这是将服务注入类的最常用方法,是将依赖项注入类的首选方式,也是微软推崇的模式。这样,除非提供了所有构造方法注入的依赖项,否则无法构造类,显示的声明了类必需的服务,使开发人员一目了然。

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>();
			// …
		}
	}
}

通过GetServiceGetRequiredService可以直接从容器中解析出我们需要的服务,这两个方法有一定的区别,推荐使用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()方法,注册一个回调,每次有类向容器中注册时,都会调用这个回调。在回调中,我们可以对当前注册的类型进行判断(一般通过接口、特性等),如果满足我们的条件,就添加一个拦截器。

image

image

image

在我们调用useAutofac()时,内部会调用UseServiceProviderFactory()创建了一个AbpAutofacServiceProviderFactory,这是实现了微软IServiceProviderFactory<>接口的一个容器工厂,任何容器提供了这个接口实现类,并且按照约定提供了ContainerBuilder,都可以作为.net core中的依赖注入容器。

在.net Core应用程序启动的时候会调用IServiceProviderFactory<>接口的CreateBuilder(IServiceCollection services)方法,我们注册的回调函数就是在这个时候执行的。遍历每一个类,在多个回调中进行执行,符合条件的都会添加一个拦截器。

image

image

最终是向autofac容器注册拦截器。

拦截器类需要实现IAbpInterceptor接口,或者继承AbpInterceptor,实现其中的InterceptAsync方法。如果对某一个类配置了拦截器,实际上它在注册到容器中时,abp会基于拦截器动态生成一个代理类,再将代理类注册到autofac中。

动态代理是基于Castle实现的。abp继承了Castle动态代理的AsyncDeterminationInterceptor,通过继承了AsyncInterceptorBase使用适配器模式将拦截器进行包装,并且将方法执行的参数进行封装传递到我们定义的拦截器中。

image

image

执行被拦截的类的方法时,实际上通过代理类在执行InterceptAsync()方法,这类似于传统过滤器的效果,所以通过这种方式,我们可以在方法执行前后添加一些和业务无关的全局的操作,即一些横切关注点。



ABP 系列总结:

目录:ABP 系列总结
上一篇:ABP - 依赖注入(1)

标签:容器,autofac,拦截器,ABP,依赖,public,注入
From: https://www.cnblogs.com/wewant/p/17125223.html

相关文章

  • 导入BaseMapper依赖需要用到的包
    <!--mp依赖mybatisPlus会自动的维护Mybatis以及MyBatis-spring相关的依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><ver......
  • WPF属性(依赖属性&附加属性)
    本篇文章学习于:刘铁猛老师《深入浅出WPF》什么是属性?属性又称为CLR属性(CLR,CommonLanguageRuntime)。我们既可以说CLR属性是private字段的安全访问包装,也可以说一个private字段在后台支持(back)一个CLR属性。classPerson{privatestringname;publicstringNam......
  • web基础漏洞-系统命令注入
    1、介绍应用程序有时需要调用一些执行系统命令的函数,如在php中,使用system、exec、shell_exec、passthru、popen、proc_popen等函数可以执行系统命令。当黑客能控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行攻击。2、windows支持的管道符|直......
  • css-select 工具包的依赖分析
    我在yarn.lock文件里看到下列这段内容,请问其语义是?css-select@^4.2.0:version"4.3.0"resolved"https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"integritysha512-wPpOYtnsVontu2mODhA19JrqWxNsf......
  • WEB漏洞—SQL注入之查询方式及报错盲注
     前言:当进行SQL注入时,有很多注入会出现无回显的情况,其中不回显的原因可能是SQL语句查询方式的问题导致,这个时候我们需要用到相关的报错或盲注进行后续操作,同时作为手工注入时,提前了解或预知其SQL语句大概写法也能更好的选择对应的注入语句。 #补充:上课的Access暴力猜......
  • 循环依赖导致编译或者服务启动报错问题:The dependencies of some of the beans in the
    错误如图: 我的是服务器启动服务时报错:***************************APPLICATIONFAILEDTOSTART***************************Description:Thedependenciesofsomeofthebeansintheapplicationcontextformacycle报错原因:两个类相互引用对方,导致Spring在初始化b......
  • Pytest - Fixture(6) - 作用域混用/执行顺序/依赖关系
    Pytest-Fixture作用域混用若测试用例调用多个不同级别的作用域,都会同时生效:conftest.pyimportpytest"""会话级别fixture,作用域当前目录"""@pytest.fixture(scope="session")deflogin_session():"""作用于整个py文件"""pr......
  • SQL注入原理及利用方式
    前言在Web表单递交或输入域名或页面请求的查询字符串,通过后端语言连接数据库并查询数据,攻击者可利用此漏洞拼接恶意语句获取大量数据。SQL注入漏洞在表单页面或者存在参数传递的地方可能存在SQL注入漏洞。SQL注入漏洞类型SQL注入类型可分为两大类:数字型注入(不需要添加特殊字......
  • WEB漏洞—SQL注入之Oracle,MongoDB等注入
     1.明确注入数据库类型、权限2.明确提交方法、参数类型等高权限可以执行文件读取,低权限就老老实实获取数据,最终目的都是获取网站权限 常见数据库类型mysql,access,mssql,mongoDB,postgresql,sqlite,oracle,sybase等1、Access注入Access与mysql结构,除access之外,其他数据库结......
  • IDEA 在pom.xml中添加maven 依赖包时下载依赖包速度很慢-解决
     IDEA在pom.xml中添加maven依赖包时下载依赖包速度很慢-解决 右键项目选中maven选项,然后选择“opensettings.xml”或者“createsettings.xml”。如果之前没有创建过,就是“createsettings.xml”,我已经修改过了,所以只出现“opensettings.xml”  <?xmlversion="......