天天看點

.net core 注入機制與Autofac

本來是要先出注入機制再出 管道 的,哈哈哈……就是不按計劃來……

這裡扯扯題外話:為什麼要注入(DI,dependency-injection),而不用 new 對象?

可能我們都很清楚,new 對象所造成的影響就是耦合度太高,DI 就是用來解耦的。或者還可以說,DI 可以統一進行管理對象。

此話怎講呢?

這裡還要擴充一下,講一下接口(Interface)跟類(Class):

接口的話通常都像 IDisposable、IEnumerable 或者 ICollection 這些一樣以 " I " 開頭命名的;而類就是繼承并實作這些接口的(當然,類不一定要繼承),比如 List 或者 Map。他們兩個都有可能是 IEnumerable 的實作,因為他們都是多繼承的實作類。

是以說,通常我們的類都是依賴于其他的。比如說我們有個 Database 的類(當然日志也行是吧),這個類主要是連接配接資料庫的。然後呢,這個類裡面,可能要做一下記錄,比如資料庫是否連接配接失敗呀,那麼就要在這個類裡面執行個體化另外一個 Logger 的類(平時的業務功能代碼實作是不是都像這樣,哈哈哈)。那麼在 Database 類裡面執行個體化了 Logger 類,它們之間就存在了依賴關系(Database 依賴 Logger)。

public class Database
    {
        public void DoSomething()
        {
            var logger = new Logger();
        }
    }      

這代碼沒毛病,但是如果突然有個需求說,我們的 Logger 不記錄在本地,我要通過 TCP/IP 記錄到另外一台伺服器上。哈,我們是不是要改代碼了……

如果我們不希望改動 Logger 裡面的代碼,那麼我們就建立多一個 TcpLogger ,那麼是不是要在項目中将所有的或者需要使用到 TcpLogger 的 Logger 類進行替換。

public class Database
    {
        public void DoSomething()
        {
            //var logger = new Logger();
            //替換成
            var logger = new TcpLogger();
        }
    }      

這方法有點蠢吧,第一,沒啥意思;第二,很容易出現錯誤,改動的地方越多,就越容易出錯;第三,有點傻,重複去做這些沒啥意思的事情,如果下次再換一種日志方式,豈不是又要改一遍?!

了解設計模式的人,很容易想到工廠模式了吧,最常用的。(但,在講注入,扯到設計模式,是不是跑題啦……)

設計模式大概怎麼搞?

ICanLog logger = new Logger();      

熟悉啵,隻要繼承 ICanLog 并且實作它,我們要什麼就 new 什麼。但這樣同樣是 new 執行個體的方式,也沒有做到,我要是換一種方式記錄日志,還是要改代碼呀。我就是忒不想改代碼的。那就試試換一種:

ICanLog logger = LoggerFactory.Create();
            //或者
            ICanLog logger = TypeFactory.Create<ICanLog>();      

這也超級熟悉的是不是。嗯,好像是要換什麼日志方式,就去改類型工廠。改的少的,但是不是有可以不改代碼的方式?

肯定是有的!我們可以通過映射(mapping)進代碼裡面。但如果在代碼裡面進行映射,還是要進行編譯。那如果把映射關系放到 XML 檔案裡面,就不用重新編譯啦。在開發中,是體會不了這種爽的。舉個栗子:

在生産環境中,如果某些原因,其中一個正在 Log 的功能運轉不了了,但是可以使用另外一種方式進行 Log,我們是不是更新一下 XML 配置檔案,替換一下就可以。(千萬别把改配置跟改代碼混為一談,完全不同!本質差別!)

OK,這裡通過 XML 配置檔案進行映射的功能,換個概念 -- IoC(Inversion of Control,控制反轉),什麼意思?

since you invert control over who decides what exact class to instantiate.
      

 簡而言之,你控制你所要使用的執行個體,就是通過(配置)控制轉化你所要使用的類執行個體。

上面所說的其實跳過了很多很多,就是怎麼實作這種映射,代碼中有怎麼決定使用哪一個執行個體呢?還是用日志舉例:就是你本來就已經寫好了兩種日志的模式,你的配置隻是确定你要使用哪一種日志模式而已,我們就可以當成這種是一種服務的定位器(就是确定我要使用的服務)。

現在的話,我們的代碼已經不再是 Logger 類了,而且依賴于這個配置。

往回看一下日志工廠或類型工廠的建立執行個體的過程,那麼注入的下一步就是獲得注入的執行個體,看代碼:

public Database(ICanLog logger) {

        }      

見鬼啦,.net core 裡見得多了吧。當然,我們現在仍然是不知道到底怎麼注入的,注入的過程是怎麼樣的,但我們已經知道為什麼要用注入了。

終于要進入主題啦 -- .net core 注入機制(.net core 提供了一個内置的服務容器 IServiceProvider,服務已在應用的 Startup.ConfigureServices 方法中注冊):引入了 Conforming Container  機制,包含了請求生命周期作用域, 服務注冊等等的統一概念。

.net core 注入機制與Autofac

看圖,看完就講完了,哈哈哈……其實圖中沒有将服務的生命周期畫出來,可以去《.net core 注入中的三種模式:Singleton、Scoped 和 Transient》看服務容器 IServiceProvider 負責管理服務的過程。這裡補重複碼字。

上圖中,我們看到一個容器,是 .net core 提供的一個容器,用來管理所注入的服務的。那麼既然有了一個容器,我們為什麼要在這篇裡面講 Autofac?Autofac 是什麼?

Autofac 是一款 Ioc 容器!

在 .net core 使用 Autofac ,我将它了解為容器的擴充與補充。(咦,可以來一篇 Autofac 的個人秀喲)

 1、.net core 沒有能處理每個請求特定的作用域;

 2、.net core 相比 Autofac,後者維護起來更友善(maintainability)、可讀性更強(readability),沒那麼容易混淆;

 3、後續繼續總結!

 .net core 與 Autofac 除了這些之外,它們之間隻是選擇而已!

PS:.net core 提供的就是構造函數的注入方式。但注入還可以是屬性的注入。屬性注入就像是選擇性依賴關系,而構造函數的注入就像是強制性依賴關系。(屬性注入跟構造函數可以下次單獨進行讨論)

繼續閱讀