首页 > 其他分享 >造轮子之自动依赖注入

造轮子之自动依赖注入

时间:2023-10-08 11:58:51浏览次数:27  
标签:原生 Autofac 依赖 builder 轮子 using 注入

在我们造轮子的起初,基建非常重要,而依赖注入是我们使用频率最高的一项,频繁的手动注入太麻烦,所以我们来实现一下自动化注入。

技术选型

在ASP.NET Core中,有两种常见的依赖注入方式:原生依赖注入和三方依赖注入。

原生依赖注入

ASP.NET Core提供了一个内置的依赖注入容器,可以用于管理应用程序中的依赖关系。原生依赖注入是ASP.NET Core框架的一部分,因此不需要额外的库或包。它提供了基本的依赖注入功能,可以满足大多数应用程序的需求。
原生依赖注入的优点:
轻量级:原生依赖注入是框架的一部分,因此不需要额外的库或包。
易于使用:它提供了简单的API,可以轻松地注册和解析依赖项。
集成性:由于是框架的一部分,原生依赖注入与ASP.NET Core的其他功能集成得很好。

原生依赖注入的缺点:
功能相对较少:原生依赖注入提供了基本的依赖注入功能,但在一些高级场景下可能不够灵活。
缺乏某些高级功能:例如,原生依赖注入不支持属性注入或命名解析等高级功能。

三方依赖注入

ASP.NET Core也支持使用第三方依赖注入容器,例如Autofac、Ninject、Unity等。这些容器提供了更多的功能和灵活性,可以满足更复杂的依赖注入需求。
三方依赖注入的优点:
功能丰富:第三方容器通常提供了更多的功能,例如属性注入、生命周期管理、条件注册等。
灵活性:使用第三方容器可以更好地控制依赖注入的行为和配置。
可扩展性:第三方容器通常提供了扩展机制,可以轻松地集成自定义解析逻辑或扩展功能。

三方依赖注入的缺点:
学习曲线:使用第三方容器可能需要一些额外的学习和配置成本。
引入外部依赖:使用第三方容器会引入额外的依赖项,增加了应用程序的复杂性。
选择使用原生依赖注入还是三方依赖注入取决于具体的需求和偏好。对于简单的应用程序,原生依赖注入通常已经足够。对于复杂的应用程序或需要更高级功能的情况,可以考虑使用第三方依赖注入容器。

既然我们需要做一个比较灵活的依赖注入,那么就选择三方的组件更合适,这里我们选用autofac。

生命周期接口

依赖注入对应有不同的生命周期,我们按照官方三种生命周期创建三个生命周期接口。
image.png
分别是
ITransientDependency 瞬态生命周期接口
IScopeDependency 范围生命周期接口
ISingletonDependency 单例生命周期接口
这些接口的定义是为了我们后续做自动化注入用的。

集成Autofac

安装Autofac的NUGET包。

分别是

Autofac.Extensions.DependencyInjection
AutoMapper.Extensions.Microsoft.DependencyInjection

替换asp.net core原生依赖注入容器

在Program中添加下面代码

using Autofac;
using Autofac.Extensions.DependencyInjection;

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

实现批量自动注入

在Autofac中有许多的注入方式,其中RegisterModule可以更方便的封装我们的注册依赖注入逻辑规则。
首先创建一个WheelAutofacModule,继承Autofac.Moudle,并重写Load方法。

using Autofac;
using Autofac.Core;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
using Wheel.DependencyInjection;
using Wheel.Domain;
using Wheel.EntityFrameworkCore;
using Module = Autofac.Module;

namespace Wheel
{
    public class WheelAutofacModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //把服务的注入规则写在这里
            var abs = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
                        .Where(x => !x.Contains("Microsoft.") && !x.Contains("System."))
                        .Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x))).ToArray();

            builder.RegisterAssemblyTypes(abs)
                .Where(t => typeof(ITransientDependency).IsAssignableFrom(t))
                .AsImplementedInterfaces()
                .AsSelf()
                .PropertiesAutowired()
                .InstancePerDependency(); //瞬态
            builder.RegisterAssemblyTypes(abs)
                .Where(t => typeof(IScopeDependency).IsAssignableFrom(t))
                .AsImplementedInterfaces()
                .AsSelf()
                .PropertiesAutowired()
                .InstancePerLifetimeScope(); //范围
            builder.RegisterAssemblyTypes(abs)
                .Where(t => typeof(ISingletonDependency).IsAssignableFrom(t))
                .AsImplementedInterfaces()
                .AsSelf()
                .PropertiesAutowired()
                .SingleInstance(); //单例.


            // 获取所有控制器类型并使用属性注入
            var controllerBaseType = typeof(ControllerBase);
            builder.RegisterAssemblyTypes(abs)
                .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
                .PropertiesAutowired();
        }
    }
}

既然我们需要批量切自动化注入,那么Autofac中RegisterAssemblyTypes根据程序集注册的方法就非常契合。
首先我们需要通过反射获取所有的dll程序集(可以加条件提前过滤已知不需要加载的程序集)。
接下来就是RegisterAssemblyTypes加载程序集,并且按照继承不同生命周期接口去注册不同的服务。
这里注意的是,如果需要使用属性注入,则需要添加PropertiesAutowired()方法。

实现WheelAutofacModule之后,我们需要在ContainerBuilder中注册一下我们的Module。
在Program中添加代码:

builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
    builder.RegisterModule<WheelAutofacModule>();
});

所有代码加起来不到100行,这样就完成了我们自动依赖注入的所有步骤了。
在后续开发中,我们所有需要注册依赖注入的服务只需要按需继承三个生命周期的接口即可。

可能有人会问使用了Autofac之后是否必须所有的服务都必须用Autofac的方式去注册服务,不能使用原生的方式。这点大可不必担心,使用autofac后,我们依然可以使用原生的AddScope等方法手动去注入我们的服务,同样是生效的。

欢迎进群催更。

image.png

标签:原生,Autofac,依赖,builder,轮子,using,注入
From: https://www.cnblogs.com/fanshaoO/p/17748524.html

相关文章

  • 造轮子之日志
    在日常使用中日志也是我们必不可少的一环,在原生日志组件中支持的日志驱动比较少,所以我们需要使用一些三方日志组件来扩展我们的日志记录。集成Serilog三方日志组件有很多,如NLOG,LOG4NET等等,这里个人习惯,使用Serilog。Serilog的集成方式非常简单。安装Nuget包Serilog.AspNetCor......
  • 造轮子之统一业务异常处理
    异常处理也是我们必不可少的一环,借助Asp.netCore的UseExceptionHandler中间件,我们可以很轻易的配置我们的业务异常处理逻辑。自定义业务异常类首先我们定义一个业务异常类,继承Exception,添加一个Code状态码属性,和MessageData数组,这个数组用于Format异常信息。在实际业务场景中可......
  • 造轮子之统一请求响应格式
    在上文中我们实现了统一业务异常处理,在异常响应中我们也使用了统一的响应格式返回给客户端。接下来我们就讲一下约定统一的氢气响应格式。在业务开发中,一个规范统一的请求响应格式可以提高我们的前后端开发对接效率,同时清晰的结构提高了可读性。响应基类首先定义一个最基础的只......
  • 使用最短路径算法检查项目循环依赖
    最近项目组让我做一个自研的小工具,用来检查代码里的循环依赖,这里做下记录。思路由于工作是网络算路的,第一个想法就是通过路径计算来实现这个功能:把项目里test,resource等文件夹排除,剩下的每一个java文件可以算是对应一个类,把每个类看做是网络/路网里的节点,把类与类之间的依赖关......
  • 异或sql注入
    来自[极客大挑战2019]FinalSQL开始以为是正常的sql注入,因为这五个都点不出东西。但是常规和非常规方法都用过了,fuzz了半天发现全给过滤完了。看了看其他wp才发现注入点就在这五个数字这里,用的知识点叫异或注入。后续就是我自己的复现了。这里有个异或注入的博客:https://w......
  • 202310061227-《心得:低版本mysql配置一,些轮子插件》
    1.对于mysql5.7.42,驱动(connector)选择:5.1.46。2.测试链接时:useSSL=true&enabledTLSProtocols=TLSv1.1 驱动链接字符串上要拼接上。3.驱动链接字符串:高版本mysql,意味着高版本connector,选>=8;低版本,选择5.x;               高版本mysql,com.my......
  • cb链子与无依赖cc构造学习
    本文默认你已经学习了cc链子依赖于cc链的构造这是cc链子中使用字节码来进执行任意命令的利用链子.PriorityQueue.readObject()PriorityQueue.heapify()PriorityQueue.siftDown()PriorityQueue.siftDownUsingComparator()......
  • intellij idea如何查看项目maven依赖关系图
    文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、有兴趣的可以关注一下。为何分享?踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。1、打开maven项目依赖打开后的效果图2、选择缩放可以选择1:1缩放、下方是效果图。3、查看......
  • spring注解开发---beans注入
    万能xml开头:<!--导入p,c命名空间context注解--><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"......
  • Spring 是如何解决循环依赖的
    首先我们要了解spring实例化bean的三步骤:1)doCreateBeanInstance,通过无参构造方法创建一个bean的实例。2)populateBean,填充bean的属性。3)initialBean,执行bean的初始化。Spring的循环依赖主要发生在第一步和第二步。Spring的依赖注入有三种情况:1.构造器注入,对于构造器注......