人與人之間都有依賴(尤其我,就是離不開女人哈哈)何況軟件呢?所謂依賴就是:當一個類需要另一個類協作來完成工作的時候就產生了依
注入體現的是一個IOC(控制反轉的的思想)
public interface IUser { string BB(); } public class User : IUser { public string BB() { return "LP整天只會BB"; } } public class ShowInfo { IUser user = new User(); public void UserBB() { user.BB(); } }
當我們調用ShowInfo的時候,是通過IUser接口實例化一個User類去實現其方法的這叫控制正傳, 但是大濕兄說,我們不應該創建User類,而是讓調用者給你傳遞,於是你通過構造函數讓外界把這兩個依賴給你。把依賴的創建丟給其它人。自己只負責使用,其它人丟給你依賴的這個過程理解為注入其它人丟給你依賴的這個過程理解為注入。也叫控制反轉(IOC)。
public interface IUser { string BB(); } public class User : IUser { public string BB() { return "LP整天只會BB"; } } public class ShowInfo2 { private readonly IUser _user; public ShowInfo2 (IUser user) { _user = user; } public void UserBB() { _user.BB(); } }
使用依賴注入我們可以很好的管理類跟類之間的依賴,在我們設計應用程序的時候遵循這幾原則,確保代碼的可維護性和擴展性;另外在Core的架構中依賴注入提供了對象創建和生命周期管理的核心能力,各個組件之間的相互協作也是由依賴注入框架來實現的
在ConfigureServices方法中的容器注冊每個應用程序的服務,Asp.Core都可以為每個應用程序提供三種服務生命周期:
Transient(暫時):每次請求都會創建一個新的實例。這種生命周期最適合輕量級,無狀態服務。
Scoped(作用域):在同一個作用域內只初始化一個實例 ,可以理解為每一個請求只創建一個實例,同一個請求會在一個作用域內。在Scooped的生存周期內,如果容器釋放 它也就被釋放了
Singleton(單例):整個應用程序生命周期以內只創建一個實例,后續每個請求都使用相同的實例。如果應用程序需要單例行為,建議讓服務容器管理服務的生命周期,而不是在自己的類中實現單例模式。
單例的沒有改變所以
Transient(暫時):每次調用服務的時候都會創建一個新的實例
Scoped(作用域):一次請求(Action)內對象實例是相同的,但每次請求會產生一個新實例。
Singleton(單例):首次請求初始化同一個實例,后續每次請求都使用同一個實例。相當於在整個應用Application中只實例化一次實例,常見的單例模式。
上面描述的比較抽象,不容易理解,用實例來講解會比較直觀。
下面通過具體的例子進行演示。
定義三個空的接口:IArticleService、IProductService、IUserService
然后定義三個實現:ArticleService、ProductService、UserService
1.將接口和實現注入到DI容器
在StartUp類的ConfigureServices方法添加下圖代碼
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.Configure<Test>(Configuration.GetSection("Test")); //演示生命周期 services.AddTransient<IUserService, UserService>(); services.AddScoped<IArticleService, ArticleService>(); services.AddSingleton<IProductService, ProductService>(); }
2.添加私有字段,在測試Controller:LifeTimeController中添加下圖代碼
private readonly IUserService _userService1; private readonly IUserService _userService2; private readonly IArticleService _articleService1; private readonly IArticleService _articleService2; private readonly IProductService _productService1; private readonly IProductService _productService2;
3.添加構造方法
public LifeTimeController( IUserService userService1, IUserService userService2, IArticleService articleService1, IArticleService articleService2, IProductService productService1, IProductService productService2 ) { _userService1 = userService1; _userService2 = userService2; _articleService1 = articleService1; _articleService2 = articleService2; _productService1 = productService1; _productService2 = productService2; }
4.添加測試代碼
public IActionResult Index() { var sb = new StringBuilder(); sb.Append("transient1:" + _userService1.GetHashCode() + "<br />"); sb.Append("transient2:" + _userService2.GetHashCode() + "<br />"); sb.Append("scope1:" + _articleService1.GetHashCode() + "<br />"); sb.Append("scope2:" + _articleService2.GetHashCode() + "<br />"); sb.Append("singleton1:" + _productService1.GetHashCode() + "<br />"); sb.Append("singleton2:" + _productService2.GetHashCode() + "<br />"); Response.ContentType = "text/html"; return Content(sb.ToString()); }
5.執行結果
第一次刷新:
transient1:66454027
transient2:35021870
scope1:38350037
scope2:38350037
singleton1:4417230
singleton2:4417230
第二次刷新:
transient1:103653
transient2:5079042
scope1:47546512
scope2:47546512
singleton1:4417230
singleton2:4417230
可見
transient類型的生命周期,每次使用都不一樣,不同的類或不同的方法使用都不一樣
scope類型的生命周期,在同一個請求內是一樣的
singleton類型的生命周期,每次請求都是一樣的
所以理解了生命周期的作用,我們在開發的時候就可以根據需要對不同的服務選擇不同的生命周期了。