.Net Core后端架构实战【介入IOC控制反转】

引言

    Inversion of Control,简称IOC,即控制反转。记得当初刚实习的时候公司的带我的人和我提到过IOC这个概念,当初完全不知道是
啥东西。后来有幸写了半年Java,SpringBoot里面业务开发随处可见IOC。再后来我写.Net Core用到的第一个框架Blog.Core项目,它里
面IRepository与Repository和IServices与Services,这种解耦的程度单说它贯彻依赖倒置原则是非常nice的!.NetCore时代更加注
重面向接口编程,并且它内置轻量型的IOC容器可帮助我们灵活的进行开发。

依赖注入

Dependency Injection,何为依赖注入?由容器动态的将对象依赖的资源注入到对象之中。假设容器在构造对象A时,对象A的构造依赖对象B、对象C、对象D这些参数,容器会将这些依赖关系自动构造好,最大限度的完成程序的解耦。依赖注入(Dependency Injection,简称DI)就是构造A对象时,需要依赖B对象,那么就先构造B对象作为参数传递到A对象,这种对象初始化并注入的技术就叫做依赖注入。

.NetCore本身就集成了一个轻量型的IOC容器,我们可以把程序中的抽象(Interface)或业务类根据需要的生命周期配置到容器中。他不是一次把所有的实例都构造出来,当你在用的时候他才会去构造实例!.NetCore内置的IOC容器只支持构造函数注入!

如下三种生命周期的注入:

Singleton:在第一次被请求的时候被创建,对象的构造函数只会执行一次然后一直会存在内存中之后就一直使用这一个实例。如果在多线程中使用了Singleton,要考虑线程安全的问题,保证它不会有冲突。

Scoped:一个请求只创建这一个实例,请求会被当成一个范围,也就是说单个请求对象的构造函数只会执行一次,同一次请求内注入多次也用的是同一个对象。假如一个请求会穿透应用层、领域层、基础设施层等等各层,在穿层的过程中肯定会有同一个类的多次注入,那这些多次注入在这个作用域下维持的就是单例。例如工作单元模式就可以借助这种模式的生命周期来实现,像EF Core的DbContext上下文就被注册为作用域服务。

Transient:每次请求时都会创建一个新的实例,只要注入一次,构造函数就会执行一次即实例化一次。Scoped、Transient的区别是你在同一个上下文中是否期望使用同一个实例,如果是,用Scoped,反之则使用Transient。

😊接下来我们来看下.Net Core中相关IOC核心源码😊

IOC源码

ServiceDescriptor

这个类是用来描述服务注册时的服务类型、实例类型、实现类型、生命周期等信息。就如同他本身的描述:Describes a service with its service type, implementation, and lifetime.       

DI容器ServiceProvider之所以能够根据我们给定的服务类型(一般是一个接口类型)提供一个能够开箱即用的服务实例,是因为我们预先注册了相应的服务描述信息,就是说ServiceDescriptor为容器提供了正确的服务信息以供容器选择对应的实例。

这个类一共有四个构造函数,本质其实就是给描述具体注册的Lifetime、ServiceType、ImplementationType、ImplementationInstance、ImplementationFactory赋值。请看源码:

这里的话只列举其中的一个构造函数,因为我发现在文章中源码不能罗列的太多,不然让人看得嫌烦😅

下面这个构造函数需要两个参数,分别是服务元素的类型,服务元素实例,默认是单例的,其它的几个构造函数都与其很相仿。

/// <summary>
/// Initializes a new instance of <see cref="ServiceDescriptor"/> with the specified <paramref name="instance"/>
/// as a <see cref="ServiceLifetime.Singleton"/>.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the service.</param>
/// <param name="instance">The instance implementing the service.</param>
public ServiceDescriptor(Type serviceType,object instance): this(serviceType, ServiceLifetime.Singleton)
{if (serviceType == null){throw new ArgumentNullException(nameof(serviceType));}if (instance == null){throw new ArgumentNullException(nameof(instance));}ImplementationInstance = instance;
}

 我们再来看下它里面几个重要的函数:

Describe()函数,可以看到这个函数也是用来生成ServiceDescriptor类的,它们分别对应上面的构造函数,也就是说为实例化ServiceDescriptor提供另外一种方式。源码如下:

private static ServiceDescriptor Describe<TService, TImplementation>(ServiceLifetime lifetime)where TService : classwhere TImplementation : class, TService
{return Describe(typeof(TService),typeof(TImplementation),lifetime: lifetime);
}/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="serviceType"/>, <paramref name="implementationType"/>,
/// and <paramref name="lifetime"/>.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="implementationType">The type of the implementation.</param>
/// <param name="lifetime">The lifetime of the service.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Describe(Type serviceType, Type implementationType, ServiceLifetime lifetime)
{return new ServiceDescriptor(serviceType, implementationType, lifetime);
}/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="serviceType"/>, <paramref name="implementationFactory"/>,
/// and <paramref name="lifetime"/>.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="implementationFactory">A factory to create new instances of the service implementation.</param>
/// <param name="lifetime">The lifetime of the service.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Describe(Type serviceType, Func<IServiceProvider, object> implementationFactory, ServiceLifetime lifetime)
{return new ServiceDescriptor(serviceType, implementationFactory, lifetime);
}

Singleton()函数,这个函数一共有七个重载,我只贴出其中三个方法,其它几个都差不多,总之就是一句话用于生成单例化的ServiceDescriptor类。源码如下:

/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
/// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <typeparam name="TImplementation">The type of the implementation.</typeparam>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Singleton<TService, TImplementation>()where TService : classwhere TImplementation : class, TService
{return Describe<TService, TImplementation>(ServiceLifetime.Singleton);
}/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="service"/> and <paramref name="implementationType"/>
/// and the <see cref="ServiceLifetime.Singleton"/> lifetime.
/// </summary>
/// <param name="service">The type of the service.</param>
/// <param name="implementationType">The type of the implementation.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Singleton(Type service, Type implementationType)
{if (service == null){throw new ArgumentNullException(nameof(service));}if (implementationType == null){throw new ArgumentNullException(nameof(implementationType));}return Describe(service, implementationType, ServiceLifetime.Singleton);
}/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="serviceType"/>, <paramref name="implementationInstance"/>,
/// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="implementationInstance">The instance of the implementation.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Singleton(Type serviceType,object implementationInstance)
{if (serviceType == null){throw new ArgumentNullException(nameof(serviceType));}if (implementationInstance == null){throw new ArgumentNullException(nameof(implementationInstance));}return new ServiceDescriptor(serviceType, implementationInstance);
}

Scoped()函数,这个函数有五个重载,其实他内部还是调用Describe()方法来生成作用域的ServiceDescriptor类。源码如下:

/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <typeparamref name="TService"/>, <typeparamref name="TImplementation"/>,
/// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <typeparam name="TImplementation">The type of the implementation.</typeparam>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Scoped<TService, TImplementation>()where TService : classwhere TImplementation : class, TService
{return Describe<TService, TImplementation>(ServiceLifetime.Scoped);
}/// <summary>
/// Creates an instance of <see cref="ServiceDescriptor"/> with the specified
/// <paramref name="service"/> and <paramref name="implementationType"/>
/// and the <see cref="ServiceLifetime.Scoped"/> lifetime.
/// </summary>
/// <param name="service">The type of the service.</param>
/// <param name="implementationType">The type of the implementation.</param>
/// <returns>A new instance of <see cref="ServiceDescriptor"/>.</returns>
public static ServiceDescriptor Scoped(Type service, Type implementationType)
{return Describe(service, implementationType, ServiceLifetime.Scoped);
}

通过Scoped()方法我们可以这样注册:

services.Add(ServiceDescriptor.Scoped<IPersonService, PersonService>());
//services.Add(ServiceDescriptor.Scoped(typeof(IPersonService),typeof(PersonService)));
//或
services.Add(ServiceDescriptor.Transient<IPersonService, PersonService>());
//services.Add(ServiceDescriptor.Transient(typeof(IPersonService), typeof(P

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/146280.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB中d2d函数用法

目录 语法 说明 示例 重新采样离散时间模型 重新采样已识别的离散时间模型 d2d函数的功能是重新采样离散时间模型。 语法 sys1 d2d(sys, Ts) sys1 d2d(sys, Ts, method) sys1 d2d(sys, Ts, opts) 说明 sys1 d2d(sys, Ts)将离散时间动态系统模型 sys 重新采样&#…

集合-List集合

系列文章目录 1.集合-Collection-CSDN博客​​​​​​ 2.集合-List集合-CSDN博客 文章目录 目录 系列文章目录 文章目录 前言 一 . 什么是List? 二 . List集合的特点 三 . 常用方法 1.void add(int index, E element): 将指定的元素插入到列表的指定位置。 2.E remove(int in…

StarRocks数据导入

1、相关环境 Flink作为当前流行的流式计算框架&#xff0c;在对接StarRocks时&#xff0c;若直接使用JDBC的方式"流式"写入数据&#xff0c;对StarRocks是不友好的&#xff0c;StarRocks作为一款MVCC的数据库&#xff0c;其导入的核心思想还是"攒微批降频率&qu…

ChatGPT App迎来重大更新;人工智能应用于应对气候变化

&#x1f989; AI新闻 &#x1f680; ChatGPT App迎来重大更新&#xff1a;增加多模态交互方式 摘要&#xff1a;OpenAI最近宣布了ChatGPT App的重大更新&#xff0c;新版的ChatGPT增加了多模态交互方式&#xff0c;用户可以向AI展示正在谈论的内容&#xff0c;比如拍照并询问…

Linux学习[21]账号与群组1---linux中/etc/passwd与/etc/shadow字段说明

文章目录 前言1. passwd字段说明2. shadow字段说明总结 前言 修改树莓派某个用户的权限到管理员权限的时候&#xff0c;涉及到了对/etc/passwd文件的修改&#xff0c;其中的字段具体含义当时也是模棱两可的&#xff0c;最近看了看相关书籍之后&#xff0c;这里做一个说明。 同…

零基础Linux_10(进程)进程终止(main函数的返回值)+进程等待

目录 1. 进程终止 1.1 main函数的返回值 1.2 进程退出码和错误码 1.3 进程终止的常见方法 2. 进程等待 2.1 进程等待的原因 2.2 wait 函数 2.3 waitpid 函数 2.4 int* status参数 2.5 int options非阻塞等待 本篇完。 1. 进程终止 进程终止指的就是程序执行结束了&…

基于树莓派CM4制作img系统镜像批量制作TF卡

文章目录 前言1. 环境与工具2. 制作镜像3. 烧录镜像4. 总结 前言 树莓派烧录完系统做定制化配置比较费时间。在面对大批量的树莓派要配置&#xff0c;那时间成本是非常巨大的。第一次配置完可以说是摸着石头过河&#xff0c;但是会弄了以后再配置&#xff0c;都是一些重复性操…

MYSQL8解压版 windows 主从部署步骤及配置(包含配置文件,教程文件,免积分下载)

MYSQL8解压版 windows 主从部署步骤及配置 一.安装MSYQL 这里只讲大概,详细步骤、my.ini文件、安装包等会在页尾文件中(正常情况按首个mysql安装,只是名字有区别) 1.主库my.ini配置 [mysqld] #典型的值是5-6GB(8GB内存)&#xff0c;8-11GB(16GB内存), 20-25GB(32GB内存)&…

【CVPR 2023】DSVT: Dynamic Sparse Voxel Transformer with Rotated Sets

文章目录 开场白效果意图 重点VoxelNet: End-to-End Learning for Point Cloud Based 3D Object DetectionX-Axis DSVT LayerY-Axis DSVT Layer Dynamic Sparse Window AttentionDynamic set partitionRotated set attention for intra-window feature propagation.Hybrid wind…

Leetcode242. 有效的字母异位词

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 解题思路&#…

(二) gitblit用户使用教程

(一)gitblit安装教程 (二) gitblit用户使用教程 (三) gitblit管理员手册 目录 网页访问git客户端设置推送错误配置查看当前配置 日常使用仓库分组my profile修改上传代码简洁 网页访问 点击Advanced... 点击Accept the Risk and Contiue 初始用户名和密码都是admin,点击login…

树莓派CM4开启I2C与UART串口登录同时serial0映射到ttyS0 开启多串口

文章目录 前言1. 树莓派开启I2C与UART串口登录2. 开启多串口总结&#xff1a; 前言 最近用CM4的时候使用到了I2C以及多个UART的情况。 同时配置端口映射也存在部分问题。 这里集中记录一下。 1. 树莓派开启I2C与UART串口登录 输入指令sudo raspi-config 跳转到如下界面&#…

中国1km土壤特征数据集(2010年)

简介&#xff1a; 中国1km土壤特征数据集&#xff08;2010&#xff09;是基于第二次全国土壤调查的中国1:1000000比例尺土壤图和8595个土壤剖面图&#xff0c;以及美国农业部&#xff08;USDA&#xff09;中国区域土地和气候模拟标准&#xff0c;开发了一个多层土壤粒度分布数…

系统接口响应信息通用加密设计

设计目的 出于对一些敏感信息的安全性考虑&#xff0c;接口的响应信息需要进行加密&#xff0c;避免明文传输 使用场景 本系统前端响应信息加密 第三方系统响应信息加密 功能设计思路 配置模式加密 使用场景&#xff1a;本系统前端响应信息加密 在nacos中配置需要加密的…

Arcgis克里金插值报错:ERROR 999999: 执行函数时出错。 表名无效。 空间参考不存在。 ERROR 010429: GRID IO 中存在错误

ERROR 999999: 执行函数时出错。 问题描述 表名无效。 空间参考不存在。 ERROR 010429: GRID IO 中存在错误: WindowSetLyr: Window cell size does not match layer cell size. name: c:\users\lenovo\appdata\local\temp\arc2f89\t_t164, adepth: 32, type: 1, iomode: 6, …

39 对称二叉树

对称二叉树 理解题意&#xff1a;如果同时满足下面的条件&#xff0c;两个树互为镜像&#xff1a;题解1 【栈】递归——DFS题解2 【队列】迭代——BFS 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 提示&#xff1a; 树中节点数目在范围 [1, 1000] 内-100 &l…

BI神器Power Query(25)-- 使用PQ实现表格多列转换(1/3)

实例需求&#xff1a;原始表格包含多列属性数据,现在需要将不同属性分列展示在不同的行中&#xff0c;att1、att3、att5为一组&#xff0c;att2、att3、att6为另一组&#xff0c;数据如下所示。 更新表格数据 原始数据表&#xff1a; Col1Col2Att1Att2Att3Att4Att5Att6AAADD…

BUUCTF reverse wp 66 - 70

[SWPU2019]ReverseMe 反编译的伪码看不明白, 直接动调 这里显示"Please input your flag", 然后接受输入, 再和32进行比较, 应该是flag长度要求32位, 符合要求则跳转到loc_E528EE分支继续执行 动调之后伪码可以读了 int __cdecl main(int argc, const char **arg…

Cesium实现动态旋转四棱锥(2023.9.11)

Cesium实现动态悬浮旋转四棱锥效果 2023.9.11 1、引言2、两种实现思路介绍2.1 思路一&#xff1a;添加已有的四棱锥&#xff08;金字塔&#xff09;模型实现&#xff08;简单但受限&#xff09;2.2 思路二&#xff1a;自定义四棱锥几何模型实现&#xff08;复杂且灵活&#xff…

面试必考精华版Leetcode199. 二叉树的右视图

题目&#xff1a; 代码&#xff08;首刷看解析&#xff09;&#xff1a; class Solution { public:vector<int> rightSideView(TreeNode* root) {unordered_map<int,int> rightmostvalue;queue<TreeNode*> nodeQueue;queue<int> depthQueue;int maxDe…