1. 學(xué)完這篇依賴注入,與面試官扯皮就沒有問題了。

        共 3437字,需瀏覽 7分鐘

         ·

        2020-10-30 04:40

        • IOC: ?Inversion Of Control 控制反轉(zhuǎn)
        • DI: ? Dependency ?Injection 依賴注入

        1.控制反轉(zhuǎn) Inversion Of Control 的前世今生

        1.1 ?IOC理論產(chǎn)生的背景

        討論控制反轉(zhuǎn)之前,先看看軟件系統(tǒng)提出控制反轉(zhuǎn)的前世今生。
        一個(gè)完整精密的軟件系統(tǒng),組件之間就像齒輪,協(xié)同工作,相互耦合。

        • 一個(gè)零件不正常,整個(gè)系統(tǒng)就崩潰了。
        • 系統(tǒng)對(duì)象之間耦合關(guān)系無法避免,在項(xiàng)目規(guī)模和復(fù)雜度變大的情況下,管理類之間的依賴關(guān)系將會(huì)很復(fù)雜。
        • 對(duì)象之間耦合度很高的系統(tǒng),架構(gòu)師和開發(fā)人員對(duì)于系統(tǒng)的修改,必然會(huì)出現(xiàn)牽一發(fā)而動(dòng)全身的情形。
        • 對(duì)象之間耦合性依賴,單元測(cè)試很復(fù)雜。

        1.2 IOC理論

        軟件專家為此提出IOC理論,用來實(shí)現(xiàn)對(duì)象之間的解耦。
        再來看看,控制反轉(zhuǎn)(IOC)到底為什么要起這么個(gè)名字?我們來對(duì)比一下:

        1. 軟件系統(tǒng)在沒有引入IOC容器之前,對(duì)象A依賴于對(duì)象B,那么對(duì)象A在初始化或者運(yùn)行到某一點(diǎn)的時(shí)候,自己必須主動(dòng)去創(chuàng)建對(duì)象B或者使用已經(jīng)創(chuàng)建的對(duì)象B。無論是創(chuàng)建還是使用對(duì)象B,控制權(quán)都在自己手上。
        2. 軟件系統(tǒng)在引入IOC容器之后,這種情形就完全改變了,由于IOC容器的加入,對(duì)象A與對(duì)象B之間失去了直接聯(lián)系,所以,當(dāng)對(duì)象A運(yùn)行到需要對(duì)象B的時(shí)候,IOC容器會(huì)主動(dòng)創(chuàng)建一個(gè)對(duì)象B注入到對(duì)象A需要的地方。
          通過前后對(duì)比,我們不難看出:
          對(duì)象A獲得依賴對(duì)象B的過程,由主動(dòng)變?yōu)榱吮粍?dòng)行為,控制權(quán)顛倒過來,這就是“控制反轉(zhuǎn)”的由來。

        1.3 控制反轉(zhuǎn) 和 依賴注入

        有些人會(huì)把控制反轉(zhuǎn)和依賴注入等同,實(shí)際上有本質(zhì)區(qū)別:
        控制反轉(zhuǎn)是一種思想;依賴注入是一種設(shè)計(jì)模式。
        依賴注入是實(shí)現(xiàn)控制反轉(zhuǎn)的一種方式,但是控制反轉(zhuǎn)還有其他實(shí)現(xiàn)方式,例如說
        ServiceLocator(服務(wù)定位器、依賴查找),所以不能將控制反轉(zhuǎn)和依賴注入等同。

        2 依賴注入 Dependency ?Injection

        依賴注入:容器全權(quán)負(fù)責(zé)組件的裝配,它會(huì)把符合依賴關(guān)系的對(duì)象通過屬性或者構(gòu)造函數(shù)傳遞給需要的對(duì)象。

        符合依賴倒置原則,高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象

        2.1 ASP.NET Core依賴注入

        使用方式大體類似:
        ①. 定義依賴實(shí)現(xiàn)的接口或者抽象類
        ②. 在服務(wù)容器中注冊(cè)組件依賴 :
        IServiceProvider
        ③. 在構(gòu)造函數(shù)中注入服務(wù), 框架會(huì)負(fù)責(zé)創(chuàng)建和銷毀實(shí)例

        //?編寫組件和服務(wù)
        public?interface?IMyDependency
        {
        ????string?WriteMessage(string?message);
        }
        ---
        public?class?MyDependency?:?IMyDependency
        {
        ????public?string?WriteMessage(string?message)
        ????{
        ???????return?$"MyDependency.WriteMessage?Message:?{message}";
        ????}
        }
        //?注冊(cè)組件和依賴,下面注冊(cè)的`IMyDependency`在一個(gè)web請(qǐng)求中有效
        public?void?ConfigureServices(IServiceCollection?services)
        {
        ????services.AddScoped();
        ????services.AddRazorPages();
        }
        ---
        //?在構(gòu)造函數(shù)注入組件
        public?class?HomeController:?AbpController
        {
        ????private?readonly?IMyDependency?_dep;
        ????public?HomeController(IMyDependency?dep)
        ????{
        ???????_dep?=?dep;
        ????}

        ??public?IActionResult?Index()
        ??{
        ????var?content?=??_dep.WriteMessage($"The?Reflection?instance?is?{_dep.GetType().FullName}?");
        ????return?Content(content);
        ??}
        }

        在請(qǐng)求某個(gè)服務(wù)時(shí),框架會(huì)完整解析出這個(gè)對(duì)象的依賴樹和作用范圍。

        上面的示例代碼形成 req--->HomeController--->IMyDependency依賴樹。

        ?IMyDependency在每個(gè)web請(qǐng)求范圍內(nèi)使用同一服務(wù)實(shí)例。

        輸出:MyDependency.WriteMessage Message: The Reflection instance is TestDI.MyDependency

        2.2 對(duì)象生命周期

        根據(jù)現(xiàn)實(shí)需要,前人從使用場(chǎng)景中總結(jié)出三種服務(wù)生命周期。
        ASP.NET Core提供了一個(gè)枚舉
        ServiceLifetime

        -----------
        Singleton單例服務(wù)容器首次請(qǐng)求會(huì)創(chuàng)建,后續(xù)都使用同一實(shí)例AddSingleton
        Scoped特定范圍在一個(gè)請(qǐng)求(連接)周期內(nèi)使用一個(gè)示例AddScoped
        Transient瞬時(shí)服務(wù)容器每次請(qǐng)求,都會(huì)創(chuàng)建一個(gè)實(shí)例AddTransient

        對(duì)于Scoped Service的理解:在webapp:scoped service 會(huì)在請(qǐng)求結(jié)束時(shí)被銷毀;
        在EFCore:使用AddDbContext默認(rèn)注冊(cè)的是特定范圍的DbContext,這意味在我們可以在一次sql連接內(nèi),使用同一個(gè)DbContext實(shí)例進(jìn)行多次DB操作。

        2.3 依賴注入實(shí)現(xiàn)原理

        結(jié)合理論、使用方式 猜測(cè)依賴注入的原理:
        實(shí)現(xiàn)DI,核心在于依賴注入容器
        IContainer,該容器具有以下功能
        ①.(容器)保存可用服務(wù)的集合
        // ?要用的特定對(duì)象、特定類、接口服務(wù)

        ②.(注冊(cè))提供一種方式將各種部件與他們依賴的服務(wù)綁定到一起;
        // ?Add...函數(shù)或containerBuilder.Register函數(shù)

        ③.(解析點(diǎn))為應(yīng)用程序提供一種方式來請(qǐng)求已配置的對(duì)象:構(gòu)造函數(shù)注入、屬性注入.

        運(yùn)行時(shí),框架會(huì)一層層通過反射構(gòu)造實(shí)例,最終得到完整對(duì)象。

        3.源碼導(dǎo)航

        利用反射產(chǎn)生對(duì)象是依賴注入的核心過程,這也是面試造航母時(shí)經(jīng)常問到的。

        .NETSystem.ReflectionSystem.Type命名空間中的類可以獲取可裝配組件、類、接口的信息,并提供了在運(yùn)行時(shí)創(chuàng)建實(shí)例,調(diào)用動(dòng)態(tài)實(shí)例方法、獲取動(dòng)態(tài)實(shí)例的能力。

        當(dāng)我嘗試從github源碼中探究[依賴注入產(chǎn)生對(duì)象]的偽代碼時(shí),文件/代碼眾多,迷路了!

        實(shí)際上,我們可以在依賴樹的尾部對(duì)象的構(gòu)造函數(shù)手動(dòng)拋出異常,異常的調(diào)用棧就是一個(gè)天然的源碼導(dǎo)航。

        于是我在上面示例代碼的request----> HomeController--->MyDependency MyDependency構(gòu)造函數(shù)中添加異常代碼:

        ????public?MyDependency()
        ????{
        ???????throw?new?Exception("exception content!");
        ????}

        結(jié)果如下圖:從Github Dependency Injection 庫(kù)進(jìn)入System.Reflection的調(diào)用分界線代碼:

        protected?override?object?VisitConstructor(ConstructorCallSite?constructorCallSite,?RuntimeResolverContext?context)
        {
        ????object[]?parameterValues;
        ????if?(constructorCallSite.ParameterCallSites.Length?==?0)
        ????{
        ?????????parameterValues?=?Array.Empty();
        ????}
        ????else
        ????{
        ???????parameterValues?=?new?object[constructorCallSite.ParameterCallSites.Length];
        ???????for?(var?index?=?0;?index???????{
        ?????????parameterValues[index]?=?VisitCallSite(constructorCallSite.ParameterCallSites[index],?context);
        ???????}
        ????}

        ????try
        ????{
        ???????return?constructorCallSite.ConstructorInfo.Invoke(parameterValues);
        ????}
        ????catch?(Exception?ex)?when?(ex.InnerException?!=?null)
        ????{
        ???????ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
        ??????//?The?above?line?will?always?throw,?but?the?compiler?requires?we?throw?explicitly.
        ??????throw;
        ?????}
        }

        黃色背景行就是.NET反射特性的體現(xiàn):
        對(duì)類型信息(構(gòu)造函數(shù)、參數(shù))使用Invoke方法產(chǎn)生對(duì)象。

        干貨旁白

        1. 控制反轉(zhuǎn)是一種在軟件工程中解耦合的思想,調(diào)用方依賴接口或抽象類,減少了耦合,控制權(quán)交給了服務(wù)容器,由容器維護(hù)注冊(cè)項(xiàng),并將具體的實(shí)現(xiàn)動(dòng)態(tài)注入到調(diào)用方。
        2. 有些人會(huì)把控制反轉(zhuǎn)和依賴注入等同,實(shí)際上有本質(zhì)區(qū)別:
          控制反轉(zhuǎn)是一種思想;
          依賴注入是一種設(shè)計(jì)模式。
          依賴注入是實(shí)現(xiàn)控制反轉(zhuǎn)的一種方式,但是控制反轉(zhuǎn)還有其他實(shí)現(xiàn)方式,例如說ServiceLocator,所以不能將控制反轉(zhuǎn)和依賴注入等同。
        3. 在運(yùn)行時(shí),框架會(huì)解析依賴樹、依賴圖,通過反射在運(yùn)行期生成對(duì)象。

        閱讀更多


        瀏覽 79
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
            
            

                      • 国产精品久久久一区二区三区网站 | www操人 | 玩弄少妇高潮A片水蜜桃网站 | 国产一级粉嫩xxxx | 台湾在线无码视频 |