重新整理 .net core 实践篇————依赖注入应用[二]
前言
这里介绍一下.net core的依赖注入框架,其中其代码原理在我的另一个整理<<重新整理 1400篇>>中已经写了,故而专门整理应用这一块。
以下只是个人整理,如有问题,望请指点。
正文
为什么有这个依赖注入呢?
假设人们面临这样一个问题。
比如说一个人做飞机去北京。那么人和飞机有什么关系呢?人和北京有什么关系呢?
假设有3个主体类,一个是人一个是飞机一个是北京。他们之间到底应该怎么组织呢?
先说人和北京的关系,人要去北京,那么飞机就是一个交通工具。是的,只是一个交通工具,那么人和飞机就没有直接的关系,而是人通过交通工具去了北京。
同样北京也可以抽象处理,北京是一个地点。那么这个语句就变成了"人通过交通工具去了某个地方",这个交通工具可以是飞机可以是高铁,未来可以是火箭。地点同样如此。
如果抓住这个词,“未来”,那么其扩展性就很强了,不仅现在拥有的还代表以后。就像我们的usb接口一样,未来可能有新的设备只要适配了usb接口,那么我主机里面的东西将不用动任何东西就可以运行新的设备。
因为我的主机没有动任何东西,那么是不是代表我的稳定性?所以依赖注入不仅可以确保我们代码的可维护性和可扩展性,最重要的是稳定性(当然了稳定性是可维护性的一种),而代码最重要的就是稳定性。
在asp.net core 的整个架构中,依赖注入框架提供了对象创建和生命周期管理的核心能力,各个组件相互协作,可以说是整个框架的核心了。
那么这里有一个关键词生命周期,将会伴随着整篇文章的核心。
.net core 的依赖实现主要是通过 Microsoft.Extensions.DependencyInjection;
其这个包,是实现了Microsoft.Extensions.DependencyInjection.Abstrations;
Microsoft.Extensions.DependencyInjection.Abstrations是接口的定义,Microsoft.Extensions.DependencyInjection 是接口的实现。
那么这里就可以想象到既然提供了接口,那么一般来说就有第三方实现,后面会介绍第三方实现。
依赖注入的核心由下面几个部门组成。
IServiceCollection 负责服务的注册
ServiceDescriptor 每一个服务注册时候的信息
IServiceProvider 具体的容器
IServiceScope 容器的子容器的生命周期
那么什么是生命周期呢?
单例模式
作用域模式
瞬时模式
那么这个怎么理解呢?首先建立起这样一个模型。

这个模型是什么意思呢? 首先我们创建单例模式产生的对象会存在root中,如果作用域模式那么创建的对象将会在某个作用域中,这个作用域是自己指定的。
而瞬时模式呢,就是不存储在任何一个作用域中。
当我们通过这个依赖注入服务创建对象的时候,如果是单例模式,那么会这么干,查找root容器中有没有该注册信息的实例,如果有就直接返回,如果没有那么创建存储在root容器中。
如果是作用域模式,那么会去找当前作用域有没有该注册信息的实例,如果有那么直接返回,如果没有那么存储在当前作用域的容器中。
同样,如果作用域模式,那么该作用域的容器消失了,里面存储的东西就没了,那么自然通过该作用域创建的对象就消失了。
那么就用代码来实验一下。
有三个类:

里面的内容就是一个接口,然后一个具体的类,这里演示其中一个。
public interface IMySingletonService
{
}
public class MySingletonService: IMySingletonService
{
}
然后再configureServices 中进行注册:
services.AddSingleton<IMySingletonService, MySingletonService>();
services.AddScoped<IMyScopedService, MyScopedService>();
services.AddTransient<IMyTransientService, MyTransientService>();
然后写一个http的get方法。
[HttpGet]
public int GetService([FromServices] IMySingletonService mySingleton1,
[FromServices] IMySingletonService mySingleton2,
[FromServices]IMyScopedService myScoped1,
[FromServices] IMyScopedService myScoped2,
[FromServices] IMyTransientService myTransient1,
[FromServices] IMyTransientService myTransient2)
{
Console.WriteLine($"singleton1:{mySingleton1.GetHashCode()}");
Console.WriteLine($"singleton1:{mySingleton2.GetHashCode()}");
Console.WriteLine($"myScoped1:{myScoped1.GetHashCode()}");
Console.WriteLine($"myScoped2:{myScoped2.GetHashCode()}");
Console.WriteLine($"myTransient1:{myTransient1.GetHashCode()}");
Console.WriteLine($"myTransient2:{myTransient2.GetHashCode()}");
return 1;
}
这里通过hashcode 来验证是否两个对象是否相等。
截图如下:

然后我们再访问一次这个接口。

上述可以得出,每一个http请求将会在同一个子容器中,且同一子容器获取的注册对象相同。而单例每次都相同。
transient 则是每次获取到不同的对象。
好了,现在生命周期明了了,下面看一下注册的方式。
我们通过这种方式进行注册:
services.AddSingleton<IMySingletonService, MySingletonService>();
那么是否还有其他方式?
还可以这样:
services.AddSingleton<IMySingletonService>(new MySingletonService());
services.AddSingleton<IMySingletonService>(ServiceProvider =>
{
return new MySingletonService();
});
为什么需要这样呢?道理也是很简单的,因为我们可能需要一些自己定制的动态参数啊。
比如说:
services.AddSingleton<IMySingletonService>(ServiceProvider =>
{
return new MySingletonService();
});
这种工厂模式,完全可以通过其他的注册服务(ServiceProvider)的参数来实例化我们的MySingletonService。
还有值得注意的是,因为我们可以多次注入。那么我们按道理可以获取到注册的全部。可以通过这种方式。
比如说:
services.AddSingleton<IMySingletonService, MySingletonService>();
services.AddSingleton<IMySingletonService>(new MySingletonService());
services.AddSingleton<IMySingletonService>(ServiceProvider =>
{
return new MySingletonService();
});
通过AddSingleton调用了3次。
[HttpGet]
public int GetService([FromServices] IEnumerable<IMySingletonService> mySingleton1)
{
foreach (var item in mySingleton1)
{
Console.WriteLine(item.GetHashCode());
}
return 1;
}
然后获取一下。

发现可以一对多了,分别获取到3个不同注册的。
那么如果我们的逻辑比较复杂,可能会多次调用到怎么破?
services.AddSingleton<IMySingletonService, MySingletonService>();
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMySingletonService, MySingletonService>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMySingletonService, MySingletonService>());
可以通过这种方式调用,如果注册信息相同就不注册,如果不同就注册。

这样就只有一个。
如果你只想注册一个的话可以这样:
services.AddSingleton<IMySingletonService, MySingletonService>();
services.TryAddSingleton<IMySingletonService, MySingletonService>();
services.TryAddSingleton<IMySingletonService, MySingletonService>();
这个就是如果有注册信息,就不再注册了。
还有其他的如替换注册信息,移除注册信息等,可以参考官网。
然后可以关注一下这个using Microsoft.Extensions.DependencyInjection.Extensions;,这里面是一些扩展的,如有自己需要的一般都在这里面了。

另一个值得注意的地方就是泛型模板的注册。
public interface IGeneticService<T>
{
public T getData();
}
public class GeneticService<T>: IGeneticService<T>
{
public T Data { get; private set; }
public GeneticService(T data)
{
this.Data = data;
}
public T getData()
{
return Data;
}
}
那么通过这种注册:
services.AddSingleton(typeof(IGeneticService<>),typeof(GeneticService<>));
然后实现一个接口:
[HttpGet]
public int GetService([FromServices] IMySingletonService mySingletonService, [FromServices] IGeneticService<IMySingletonService> geneticService)
{
Console.WriteLine(geneticService.getData().GetHashCode());
Console.WriteLine(mySingletonService.GetHashCode());
return 1;
}

结
这里埋了一个点:
services.AddSingleton<IMySingletonService, MySingletonService>();
services.AddSingleton<IMySingletonService>(new MySingletonService());
services.AddSingleton<IMySingletonService>(ServiceProvider =>
{
return new MySingletonService();
});
那就是上面这三种注册方式的对象释放行为是不一样的,如果不了解的话,那么可能你的服务跑着跑着内存就跑高了。下一节将会解释到。
上述只是个人整理,如有错误,望请指出,谢谢,一天一更。上述只是应用,如代码原理,请查看<<重新整理.net core 1400篇>>。
重新整理 .net core 实践篇————依赖注入应用[二]的更多相关文章
- 重新整理 .net core 实践篇————依赖注入应用之援军[四]
前言 介绍第三方依赖注入框架Autofac,看看为我们解决什么问题. 下面介绍4个点: 命名注册 属性注册 aop 注入 子容器命名 正文 为什么我们需要使用第三方框架?第三方框架为我们做了什么?第三 ...
- 重新整理 .net core 实践篇————依赖注入应用之生命法则[三]
前言 该章演示依赖注入中,对象的释放行为. 紧接上文表示,演示: services.AddSingleton<IMySingletonService, MySingletonService> ...
- 重新整理 .net core 实践篇—————HttpClientFactory[三十二]
前言 简单整理一下HttpClientFactory . 正文 这个HttpFactory 主要有下面的功能: 管理内部HttpMessageHandler 的生命周期,灵活应对资源问题和DNS刷新问 ...
- 重新整理 .net core 实践篇—————工作单元模式[二十六]
前言 简单整理一下工作单元模式. 正文 工作单元模式有3个特性,也算是其功能: 使用同一上下文 跟踪实体的状态 保障事务一致性 工作单元模式 主要关注事务,所以重点在事务上. 在共享层的基础建设类库中 ...
- 重新整理 .net core 实践篇—————路由和终结点[二十三]
前言 简单整理一下路由和终节点. 正文 路由方式主要有两种: 1.路由模板方式 2.RouteAttribute 方式 路由约束: 1.类型约束 2.范围约束 3.正则表达式 4.是否必选 5.自定义 ...
- 重新整理 .net core 实践篇————配置应用[一]
前言 本来想整理到<<重新整理.net core 计1400篇>>里面去,但是后来一想,整理 .net core 实践篇 是偏于实践,故而分开. 因为是重新整理,那么就从配置开 ...
- ASP.NET Core之依赖注入
本文翻译自:http://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core ASP.NET Core支持依赖注入,依赖 ...
- 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入
系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...
- 几十行代码实现ASP.NET Core自动依赖注入
在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步 ...
随机推荐
- python中gzip模块的使用
gzip模块能够直接压缩和解压缩bytes-like类型的数据,同时也能实现对应格式文件的压缩与解压缩 一.数据压缩与解压缩 压缩 函数-gzip.compress(data, compresslev ...
- 庐山真面目之十三微服务架构中如何在Docker上使用Redis缓存
一.介绍 1.开始说明 在微服务器架构中,有一个组件是不能少的,那就是缓存组件.其实来说,缓存组件,这个叫法不是完全正确,因为除了缓存功能,它还能完成其他很多功能.我就不隐瞒了,今天我们要探讨 ...
- Sentinel全局Feign默认熔断设计实现
写在前面 用XMind画了一张导图记录Spring Cloud Alibaba的学习笔记(源文件对部分节点有详细备注和参考资料,由于太大就没展示全部,欢迎关注我的公众号:阿风的架构笔记 后台发送[导图 ...
- OO第四单元——基于UML的UML解析器总结&OO课程总结
OO第四单元--基于UML的UML解析器总结&OO课程总结 前言:一学期愉快(痛苦)的OO课程学习结束了,OO几个单元作业都各有特色,实验也各有特色,仔细回味起来,不再是单纯的敲代码(但自己还 ...
- UnitOneSummary
目录 一.程序结构分析 第一次作业 第二次作业 第三次作业 二.Test & Bugs 三.设计模式 四.总结与反思 一.程序结构分析 第一次作业 思路: 1.输入预处理: 去除空格和\t 替 ...
- (十一)struts2的未知处理器
从struts2.1开始,struts2增加了未知处理器. 当用户请求未知Action,或指定Action里的未知方法,或Action处理结束后返回一个未知的result.struts2允许使用未知处 ...
- MySQL提升笔记(2):存储引擎盘点
在前面我们了解了server层调用存储引擎层接口来完成sql的执行,使用存储引擎的好处是:每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表. 需要注意的是,存储引擎是基于表的,而不是数 ...
- 并发编程-线程池&J.U.C
8. 共享模型之工具 8.1 线程池 池化技术相比大家已经屡见不鲜了,线程池.数据库连接池.Http 连接池等等都是对这个思想的应用.池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率 ...
- 分库分表之后,id主键如何处理?
(1)数据库自增id 这个就是说你的系统里每次得到一个id,都是往一个库的一个表里插入一条没什么业务含义的数据,然后获取一个数据库自增的一个id.拿到这个id之后再往对应的分库分表里去写入. 这个方案 ...
- gateway调用Fegin失败问题解决
起因 新项目用的是springcloud2.0,网关用gateway替换了zuul. gateway动态路由跟zuul有本质上的区别.这就涉及到webflux这一套大东东了.简单来说,gateway是 ...