前篇已經介紹了依賴註入與服務發現,還有另外一種機制是服務部署,顧名思義就是可以在程式集中定義一個實現,在手動添加依賴註入,這一般是有選擇性的註入。 ...
目錄
- Fireasy3 揭秘 -- 依賴註入與服務發現
- Fireasy3 揭秘 -- 自動服務部署
- Fireasy3 揭秘 -- 使用 SourceGeneraor 改進服務發現
- Fireasy3 揭秘 -- 使用 SourceGeneraor 實現動態代理(AOP)
前篇已經介紹了依賴註入與服務發現,還有另外一種機制是服務部署,顧名思義就是可以在程式集中定義一個實現,在手動添加依賴註入,這一般是有選擇性的註入。
回顧 DefaultServiceDiscoverer
類,你會發現有這麼一個 ConfigureServices
方法,前篇是沒有介紹過的,專門提到本篇里來細說。如下:
/// <summary>
/// 發現工作目錄中所有程式集中的依賴類型。
/// </summary>
/// <param name="services"></param>
private void DiscoverServices(IServiceCollection services)
{
foreach (var assembly in GetAssemblies())
{
if (_options?.AssemblyFilters?.Any(s => s.IsFilter(assembly)) == true)
{
continue;
}
if (_options?.AssemblyFilterPredicates?.Any(s => s(assembly)) == true)
{
continue;
}
_assemblies.Add(assembly);
ConfigureServices(services, assembly);
DiscoverServices(services, assembly);
}
}
在 ConfigureServices
方法里,通過 ServicesDeployAttribute
特性去查找程式集中定義的部署類。所謂部署類,實際上是往 services 里添加服務描述(服務與實現的關係映射)。如下:
private void ConfigureServices(IServiceCollection services, Assembly assembly)
{
var attrs = assembly.GetCustomAttributes<ServicesDeployAttribute>();
if (attrs.Any())
{
foreach (var attr in attrs.OrderBy(s => s.Priority))
{
if (Activator.CreateInstance(attr.Type) is IServicesDeployer deployer)
{
deployer.Configure(services);
}
}
}
else
{
var types = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && typeof(IServicesDeployer).IsAssignableFrom(t)).ToList();
var deployers = types
.Select(s => Activator.CreateInstance(s))
.Where(s => s is IServicesDeployer)
.Cast<IServicesDeployer>()
.ToList();
deployers.ForEach(s => s!.Configure(services));
}
}
它首先會通過 ServicesDeployAttribute
特性去找所指定的部署類,這樣的好處在於直達終點,省去了遍列程式集中的所有類,逐個去判斷有沒有實現了 IServicesDeployer
介面。找到這些部署類後,實例化一個對象,調用 Configure
去配置容器。
採用這種部署器後,你只需要在你的程式集里定義一個實現 IServicesDeployer
介面的類,想怎麼 Add 就怎麼 Add,靈活性要高。比如在 Fireasy.Data 項目中,就可以定義如下:
[assembly: ServicesDeploy(typeof(DataServicesDeployer))]
namespace Fireasy.Data.DependencyInjection
{
/// <summary>
/// 服務部署。
/// </summary>
public class DataServicesDeployer : IServicesDeployer
{
void IServicesDeployer.Configure(IServiceCollection services)
{
services.AddSingleton<IProviderManager, DefaultProviderManager>();
services.AddSingleton<IDatabaseFactory, DefaultDatabaseFactory>();
services.AddSingleton<IRowMapperFactory, DefaultRowMapperFactory>();
services.AddScoped<IDatabase>(sp => sp.GetRequiredService<IDatabaseFactory>().CreateDatabase());
services.AddScoped<DistributedController>();
}
}
}
你可以不用關註它在什麼時候被部署,因為只要在起先調用了 AddFireasy 方法後,它就被不知不覺調用了。
同一個程式集里可以存在多個部署類,ServicesDeployAttribute
也是允許多次指定的,甚至可以使用 Priority 來指定被部署的優先順序。
最後,奉上 Fireasy 3
的開源地址:https://gitee.com/faib920/fireasy3 ,歡迎大家前來捧場。
本文相關代碼請參考:
https://gitee.com/faib920/fireasy3/src/libraries/Fireasy.Common/DependencyInjection
更多內容請移步官網 http://www.fireasy.cn 。
作者:fireasy出處:http://fireasy.cnblogs.com
官網:http://www.fireasy.cn
版權聲明:本文的版權歸作者與博客園共有。轉載時須註明本文的詳細鏈接,否則作者將保留追究其法律責任。