標籤:src efault icon lis stat github default 上下 pat
05、NetCore2.0外掛程式架構運行原理之WebHostBuilder源碼初窺
NetCore2.0的外掛程式架構是要解決對象建立的問題,把建立對象與使用對象進行解耦。調用者不需要關心對象是單例的還是多執行個體的;外掛程式的擴充和調用也更容易。
一、我們先看看外掛程式架構是如何使用的
首先使用VS2017建立一個控制台程式,要使用外掛程式架構,我們需要引入微軟的依賴注入包:
install-package Microsoft.Extensions.DependencyInjection
我們聲明一個自己的介面,並實現一個類
// 介面interface IRun { void Run(); }// 實作類別class Run : IRun { void IRun.Run() { Console.WriteLine("跑起來,兄弟"); } }
使用外掛程式架構來註冊介面和類的執行個體;並通過服務提供者來提供者
using Microsoft.Extensions.DependencyInjection;using System;namespace MyServiceBus{ class Program { static void Main(string[] args) { // 執行個體化服務外掛程式架構 IServiceCollection services = new ServiceCollection(); // 在服務外掛程式架構中加入介面的一個執行個體(它是單例的) services.AddSingleton<IRun, Run>(); // 服務外掛程式的提供者 IServiceProvider serviceProvider = services.BuildServiceProvider(); // ============上下兩部分代碼一般不會同時出現在一個類中======== // 從服務外掛程式提供者擷取介面的執行個體(不用關心是如何建立的) serviceProvider.GetService<IRun>().Run(); Console.ReadLine(); } }}
看看運行效果吧!可以看出,IRun業務的調用方,不需要關心是如何執行個體化的。
二、在Asp.NetCore2.0中外掛程式架構是如何使用的
一個極簡的Web應用程式一般是這樣的:
using Microsoft.AspNetCore.Hosting;namespace MyWebApi{ class Program { static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseStartup<StartUp>() .Build(); host.Run(); } }}
從上面的代碼中判斷,外掛程式架構的初始化和介面註冊應該是在WebHostBuild.Build()方法中完成的,從命名就能看出,這是一個建造者模式,把內部複雜的構建方式隱藏了。我們去看一下這個方法的開原始碼:
// 為了說明問題,代碼略作調整,保留核心代碼
public IWebHost Build() { // 初始化服務外掛程式架構:估計裡面預製了一些服務外掛程式 IServiceCollection hostingServices = BuildCommonServices(out var hostingStartupErrors); IServiceCollection applicationServices = hostingServices.Clone();
// 服務外掛程式的提供者 ServiceProvider hostingServiceProvider = hostingServices.BuildServiceProvider(); AddApplicationServices(applicationServices, hostingServiceProvider); var host = new WebHost( applicationServices, hostingServiceProvider, _options, _config, hostingStartupErrors); host.Initialize(); return host; }
我們可以看到在WebHostBuild.Build()方法中,顯示的初始化了服務外掛程式架構,我們看一下服務外掛程式架構初始化方法的源碼,可以發現確實預製了一些服務:
// 為了說明問題,代碼略作調整,保留核心代碼 private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors) { // 配置選項 _options = new WebHostOptions(_config); var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, AppContext.BaseDirectory); var applicationName = _options.ApplicationName; // Initialize the hosting environment _hostingEnvironment.Initialize(applicationName, contentRootPath, _options); _context.HostingEnvironment = _hostingEnvironment; // 執行個體化服務外掛程式架構 var services = new ServiceCollection(); // 預製環境參數外掛程式到架構中 services.AddSingleton(_hostingEnvironment); // 預製上下文外掛程式到架構中 services.AddSingleton(_context); // 預製組態管理外掛程式到架構中 var builder = new ConfigurationBuilder() .SetBasePath(_hostingEnvironment.ContentRootPath) .AddInMemoryCollection(_config.AsEnumerable()); var configuration = builder.Build(); services.AddSingleton<IConfiguration>(configuration); _context.Configuration = configuration; // 預製診斷工具外掛程式到架構中 var listener = new DiagnosticListener("Microsoft.AspNetCore"); services.AddSingleton<DiagnosticListener>(listener); services.AddSingleton<DiagnosticSource>(listener); // 預製診斷其他外掛程式到架構中 services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>(); services.AddTransient<IHttpContextFactory, HttpContextFactory>(); services.AddScoped<IMiddlewareFactory, MiddlewareFactory>(); services.AddOptions(); services.AddLogging(); // Conjure up a RequestServices services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>(); services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>(); // Ensure object pooling is available everywhere. services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>(); return services; }
從程式碼分析看WebHostBuilder做的事如下:
1. 定義了一些WebHost的配置項
2. 建立依賴注入的容器, 並預製一些service
05、NetCore2.0外掛程式架構運行原理源碼初窺