我用段子讲.NET之依赖注入其二
《我用段子讲.NET之依赖注入其二》
”随着我们将业务代码抽象化成接口和实现两部分,这也使得对象生命周期的统一管理成为可能。这就引发了第二个问题,.NET Core中的依赖注入框架。”
1
听到董哥这么说,作为一位仅有3年左右经验的开发者小木同学一脸错愕,虽然这句话的每个词他都认识,但连在一起却犹如听天书。
”董哥,你说的第一句话,我倒是刚刚已经听你说明白了。但这第二句话却完全搞不懂。主要有两个问题,第一,什么叫做对象生命周期,其次,怎么实现统一管理的?”
董哥莞尔一笑:”那你觉得.NET对象是如何创建和销毁的?”
小木同学对这个话题并不陌生,他说:”对象的创建,一般用new关键词来创建,对象的销毁则一般使用对象继承自IDisposable,并在析构函数中释放。不过析构函数这种用法都是我在网上看到的,实际上没用过,这就属于对象生命周期管理吧?”
董哥说:”是的。”
小木继续说:”那按这个说法,我感觉.NET中不用刻意维护对象生命周期,垃圾回收机制会回收超出生命周期的对象吧。 ”
“事实上虽然.NET虽然会通Gc管理对象生命周期,实际上依然会面临这样的问题。这有点像我们可能看不到地球的存在,但我们存在,那地球也是客观存在的,只是平时我们没注意观察而已。
那你们的代码里面,估计没刻意控制过对象的创建过程,而且估计也经常使用静态变量吧。”
“额,是啊,我司生产代码里面出现得最多的,估计就是new 对象的语句,以及定义为public static的静态变量了,有一次我认真的观察了一下,几乎每个类都会定义几个静态变量。”
听到小木这么说,董哥被逗乐了:“听起来有点搞笑,不过我也知道,你们这种HIS系统,本来就是业务非常复杂,如何快速的完成项目才最重要。“
2
董哥看到小木的杯子空了,又去给他加了一点水。
这时董哥窗外的湖面也掩映着一片夕阳的灿烂,微风吹过,粼粼波光,风景倒是挺雅致,不知不觉,已经临近6点半,他们围绕这个话题已经聊了快个把小时了,此时董哥他们办公室也迎来了下班高峰期,同事们渐次的离开办公室,但对技术爱好者来说,总是感觉不到时间流逝。
董哥回来后,把杯子递给小木,同时,也拿起自己的杯子喝了一口,他慢条斯理的说:
“在许多业务系统开发里面,内存仿佛不要钱,大不了就给医生们多加几根内存条,反正都是地方财政买单,也不会要开发人员出钱。再者,估计买内存条的钱,显然比优化代码付出的成本低,花那么多时间优化性能,有时确实反而付出了更高的时间成本。
而对于我们物联网嵌入式系统开发者来说,硬件基础设施都金贵着,有时稍微注意点,配置可能看起来差不多,但总价可以省出好几十块钱一台出来。如果生产量比较多,还能多赚不少钱。当然,并不是说.NET就不行,我们有的应用其实也在用.NET Core来开发,性能还挺不错的。“
小木也端起杯子喝了一口,回答道:
“也许只是我们公司是这样吧,估计那些大一点的公司会好许多。也有可能是.NET入门容易,没.NET Core那么多套路,所以很容易就放飞了。
那在.NET Core里面依赖注入框架是如何统一管理对象生命周期的?”
3
董哥继续拿起了那张画了一棵树的纸,他说:”不仅对象间的依赖关系本身像一棵树,对象的生命周期管理,其实也像这一棵树。首先是主程序不断的new对象,然后对象再不断的new子对象。就像主干长出枝干,枝干长出叶子,结构越来越复杂。但对象如果不断的堆积在内存中,就会引发内存泄漏(oom)问题,导致程序崩溃。你听过值对象和引用对象么?“
小木点了点头:“听说值对象放在栈上,引用对象放在堆上。”
“是的,当然,值对象在业务开发中可能用得没那么多,所以造成内存占用的,主要还是放在堆上的对象。垃圾回收策略倒是只有一句话,引用计数,分代回收,对象压缩。0代,1代,2代,大对象堆,分别有不同的回收策略。不过这些可能对你来说理解暂时有点困难,有机会再慢慢说。“
”比较容易理解的可能是,对象回收并非一直在发生,它只有在系统物理内存不足,达到内存回收阈值,手动调用GC.Collect方法等情况下发生。而且垃圾回收过程并非对程序毫无副作用,在某些性能要求特别高的场景,例如高并发场景下,发生计划外的垃圾回收,可能会导致程序偶发性变得卡顿,可能会造成用户体验度的下降。这也是痛点,也就是依赖注入框架所能解决的第二个问题。统一的生命周期管理“
董哥突然变得严肃起来。
“在.NET Core中,ASP.NET Core内置了依赖注入容器IServiceCollection和服务提供者IServiceProvider。对开发者来说,通过建立抽象,提取出接口或基类,再将该对象注册到依赖注入容器中。
在服务调用时,上层应用不再通过new的形式使用下层接口,而是在构造函数中,通过引入依赖注入框架实例化的下层实现,并由该框架来统一管理对象的生命周期。
这就是依赖注入框架所采取的手段。”
4
“听起来还是挺不错的,就是对开发者的操作习惯造成了一些影响。”木哥叹息道。
董哥点了点头,“对许多开发者来说,改变习惯如同断人财路。我也曾经见过很多开发者特别喜欢使用全局静态变量,仿佛不用静态变量就不会写代码了。事实上对专业开发者来说,出现的每一个静态变量都会让其产生很痛苦的感觉。
首先,全局静态变量由root根来进行管理的对象,除非应用程序退出,这些对象几乎不会释放。如果开发者再玩一些骚操作,例如用全局静态变量来存放集合,有时会成为gc的一场灾难片。
其次,全局静态变量就是单例对象,全局只会出现一次实例,并发访问时,很容易就会引发线程安全问题。线程安全问题看起来简单,实则是软件开发中最难处理的一类问题了。为了一劳永逸,有的开发者习惯于用lock
语句来强制使之同步化,这又使得应用程序很难充分利用硬件性能带来的优势。
所以,开发者有时改变一些思维定势,例如尽量不要出现全局静态变量,如果一定要出现,也推荐使用依赖注入框架所提供的单例生命周期来管理,这样使得整个应用系统的生命周期管理都处于可控状态。当然,全局静态方法是允许存在的,类似于 public static string xxx
这样的扩展方法,可以使开发者的代码变得非常优雅。
在我看来,定义接口,通过依赖注入框架注册对象,通过构造函数创建对象,看起来非常简单的三个步骤,却有可能使应用系统开发变得更加的高可控,仅就这么一个小小的变化,就已经显得.NET Core开发比传统.NET 开发更加的充满魅力和神奇。“
5
董哥一时激动,讲了许多在木哥看来有点完全搞不懂的概念。这也使得小木突然间一脸懵逼,不知道该如何接下这个话题,半响之后,他才逐渐吐出一个问题:”董哥,你说的单例生命周期是啥意思?我在.NET Core开发中好像隐约看到过,但有点不太理解它的含义,你能跟我简单讲一下么。“
董哥也意识到自己突然间聊嗨了,兀自的笑了一笑,然后说:“
在.NET Core提供的依赖注入框架中,提供了三种不同的生命周期。
第一种就是SingleTon单例生命周期,这种模式有点像设计模式中的单例模式,通俗而言,就是在软件的整个生命周期只会出现唯一一次实例,并随着应用程序的结束而销毁。他有点像全局静态变量,只是整个过程都由依赖注入框架管理。许多全局变量都可以通过该生命周期所提供的服务层维护。
第二种就是Scoped生命周期,用中文翻译有点像作用域,这个作用域如何理解呢,我们都知道,http请求实际上是以为会话的形式进行的,每个会话往往会有IIS宿主开辟独立的线程来进行支持,那么这个作用域大概就像是给每个会话开辟的独立线程。在这个线程的生命周期内,开发者都能从依赖注入框架中,便捷的引入适当的服务层来提供业务支持。
第三种则是Transient生命周期,瞬时生命周期。一瞬间就过去了,说明时间很快。当然,如果用一句佛经来形容,那就是
一刹那者为一念,二十念为一瞬,二十瞬为一弹指,二十弹指为一罗预,二十罗预为一须臾,一日夜有三十须臾。
这个一瞬间,大概是0.36秒,实际上程序执行可能比这快很多。程序语言目前还无法跟佛经对应起来,我们只能把它理解为,一次方法调用过程为瞬时。一般是那种需要随用随取的对象,主要是相对于Scoped而言的,在控制台应用中使用非常广泛。
.NET Core提供的这三种生命周期,看起来很简单,但有时候也比较容易就踩坑了,这就需要我们平时注意自己的使用习惯了。“
6
一晃围绕这个话题,他们已经聊了一个半小时,随着窗外夕阳的逐渐消逝,窗外初上的华灯也使两位大佬意识到时间不早了,于是,他们也离开了办公室。
--end
我用段子讲.NET之依赖注入其二的更多相关文章
- 我用段子讲.NET之依赖注入其一
<我用段子讲.NET之依赖注入其一> 1) 西城的某个人工湖畔,湖水清澈见底,湖畔柳树成荫.人工湖往北,坐落着两幢写字楼,水晶大厦靠近地铁站,由于为了与湖面天际线保持一致,楼层只有26层高 ...
- 依赖注入及AOP简述(九)——单例和无状态Scope .
三.依赖注入对象的Scope及其生命周期 在前面的章节我们讲到,依赖注入容器之所以能够区别于以往的ServiceLocator等容器,是在于其不但能够自动构建多层次的.完整的依赖关系图,并且可以管理依 ...
- 依赖注入及AOP简述(十二)——依赖注入对象的行为增强(AOP) .
四.依赖注入对象的行为增强(AOP) 前面讲到,依赖注入框架的最鲜明的特点就是能够提供受容器管理的依赖对象,并且可以对对象提供行为增强(AOP)功能,所以这一章我们来讨论有关AOP的话题. 1. ...
- (转)编码剖析Spring依赖注入的原理
http://blog.csdn.net/yerenyuan_pku/article/details/52834561 Spring的依赖注入 前面我们就已经讲过所谓依赖注入就是指:在运行期,由外部容 ...
- angular2系列教程(八)In-memory web api、HTTP服务、依赖注入、Observable
大家好,今天我们要讲是angular2的http功能模块,这个功能模块的代码不在angular2里面,需要我们另外引入: index.html <script src="lib/htt ...
- Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现
0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...
- ABP(现代ASP.NET样板开发框架)系列之6、ABP依赖注入
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...
- ABP源码分析六:依赖注入的实现
ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(6)-Unity 依赖注入
系列目录 前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 本节重构一下代码,采用IOC控制反转,也就是依赖注入 您可以访问http://unity.codeplex.com/rel ...
随机推荐
- IT菜鸟之网线制作
网线是属于OSI七层模型中的物理层:网络中的数据传输媒介 备注:OSI七层模型后面会记录 网线制作所需要的资源素材: 1.网线 2.水晶头(类型:电话线RJ11,宽带线RJ45) 3.网线钳(非必需) ...
- linux进阶之远程免密登录,动态添加磁盘及个别基础命令
一. 免密登录(远程连接ssh) ssh IP #连接登录到其它机 ssh 192.168.10.102 ssh IP "CMD" #在其它机器上执行命令 yum -y i ...
- 9.11 strace:跟踪进程的系统调用 、ltrace:跟踪进程调用库函数
strace 是Linux环境下的一款程序调试工具,用于检查一个应用程序所使用的系统调用以及它所接收的系统信息.strace会追踪程序运行时的整个生命周期,输出每一个系统调用的名字.参数.返回值和执行 ...
- Java读取SQL server数据库
要打开SQL server 的三个服务,然后再执行代码. package com.sql; import java.sql.SQLException; import java.sql.Statemen ...
- Wide & Deep的OneFlow网络训练
Wide & Deep的OneFlow网络训练 HugeCTR是英伟达提供的一种高效的GPU框架,专为点击率(CTR)估计训练而设计. OneFlow对标HugeCTR搭建了Wide & ...
- Jittor 的Op, Var算子
Jittor 的Op, Var算子 要使用jittor训练模型,需要了解两个主要概念: Var:Jittor的基本数据类型 Operations:Jittor的算子与numpy类似 首先,开始使用Va ...
- ARM Cortex-M嵌入式C基础编程(下)
ARM Cortex-M嵌入式C基础编程(下) ARM Cortex-M Embedded C Fundamentals/Tutorial -Aviral Mittal Load Region Vs ...
- NVIDIA® TensorRT™ supports different data formats
NVIDIA TensorRT supports different data formats NVIDIATensorRT公司 支持不同的数据格式.需要考虑两个方面:数据类型和布局. ...
- 实时双频Wi-Fi如何实现下一代车内连接
实时双频Wi-Fi如何实现下一代车内连接 How real simultaneous dual band Wi-Fi enables next-generation in-vehicle connec ...
- Spring Cloud03: Eureka Client 服务提供者
一.创建一个子工程并引入配置如下: <dependency> <groupId>org.springframework.cloud</groupId> <ar ...