博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动手造轮子:实现一个简单的依赖注入(二) --- 服务注册优化
阅读量:3966 次
发布时间:2019-05-24

本文共 6309 字,大约阅读时间需要 21 分钟。

动手造轮子:实现一个简单的依赖注入(二) --- 服务注册优化

Intro

之前实现的那版依赖注入框架基本可用,但是感觉还是不够灵活,而且注册服务和解析服务在同一个地方感觉有点别扭,有点职责分离不够。于是借鉴 Autofac 的做法,增加了一个 ServiceContainerBuilder 来负责注册服务,ServiceContainer负责解析服务,并且增加了一个 ServiceContainerModule 可以支持像 Autofac 中 Module/RegisterAssemblyModules 一样注册服务

实现代码

ServiceContainerBuilder

增加 ServiceContainerBuild 来专门负责注册服务,原来注册服务的那些扩展方法则从 IServiceContainer 的扩展方法变成 IServiceContainerBuilder 的扩展

public interface IServiceContainerBuilder{    IServiceContainerBuilder Add(ServiceDefinition item);    IServiceContainerBuilder TryAdd(ServiceDefinition item);    IServiceContainer Build();}public class ServiceContainerBuilder : IServiceContainerBuilder{    private readonly List
_services = new List
(); public IServiceContainerBuilder Add(ServiceDefinition item) { if (_services.Any(_ => _.ServiceType == item.ServiceType && _.GetImplementType() == item.GetImplementType())) { return this; } _services.Add(item); return this; } public IServiceContainerBuilder TryAdd(ServiceDefinition item) { if (_services.Any(_ => _.ServiceType == item.ServiceType)) { return this; } _services.Add(item); return this; } public IServiceContainer Build() => new ServiceContainer(_services);}

IServiceContainer

增加 ServiceContainerBuilder 之后就不再支持注册服务了,ServiceContainer 这个类型也可以变成一个内部类了,不必再对外暴露

public interface IServiceContainer : IScope, IServiceProvider{    IServiceContainer CreateScope();}internal class ServiceContainer : IServiceContainer{    private readonly IReadOnlyList
_services; public ServiceContainer(IReadOnlyList
serviceDefinitions) { _services = serviceDefinitions; // ... } // 此处约省略一万行代码 ...}

ServiceContainerModule

定义了一个 ServiceContainerModule 来实现像 Autofac 那样,在某一个程序集内定义一个 Module 注册程序集内需要注册的服务,在服务注册的地方调用 RegisterAssemblyModules 来扫描所有程序集并注册自定义 ServiceContainerModule 需要注册的服务

public interface IServiceContainerModule{    void ConfigureServices(IServiceContainerBuilder serviceContainerBuilder);}public abstract class ServiceContainerModule : IServiceContainerModule{    public abstract void ConfigureServices(IServiceContainerBuilder serviceContainerBuilder);}

自定义 ServiceContainerModule 使用示例:

public class TestServiceContainerModule : ServiceContainerModule{    public override void ConfigureServices(IServiceContainerBuilder serviceContainerBuilder)    {        serviceContainerBuilder.AddSingleton
(GuidIdGenerator.Instance); }}

RegisterAssemblyModules 扩展方法实现如下:

public static IServiceContainerBuilder RegisterAssemblyModules(    [NotNull] this IServiceContainerBuilder serviceContainerBuilder, params Assembly[] assemblies){    #if NET45        // 解决 asp.net 在 IIS 下应用程序域被回收的问题        // https://autofac.readthedocs.io/en/latest/register/scanning.html#iis-hosted-web-applications        if (null == assemblies || assemblies.Length == 0)        {            if (System.Web.Hosting.HostingEnvironment.IsHosted)            {                assemblies = System.Web.Compilation.BuildManager.GetReferencedAssemblies()                    .Cast
().ToArray(); } } #endif if (null == assemblies || assemblies.Length == 0) { assemblies = AppDomain.CurrentDomain.GetAssemblies(); } foreach (var type in assemblies.WhereNotNull().SelectMany(ass => ass.GetTypes()) .Where(t => t.IsClass && !t.IsAbstract && typeof(IServiceContainerModule).IsAssignableFrom(t)) ) { try { if (Activator.CreateInstance(type) is ServiceContainerModule module) { module.ConfigureServices(serviceContainerBuilder); } } catch (Exception e) { Console.WriteLine(e); } } return serviceContainerBuilder;}

使用示例

使用起来除了注册服务变化了之外,别的地方并没有什么不同,看一下单元测试代码

public class DependencyInjectionTest : IDisposable{    private readonly IServiceContainer _container;    public DependencyInjectionTest()    {        var containerBuilder = new ServiceContainerBuilder();        containerBuilder.AddSingleton
(new ConfigurationBuilder().Build()); containerBuilder.AddScoped
(); containerBuilder.AddScoped
(); containerBuilder.AddScoped
(); containerBuilder.AddScoped
(); containerBuilder.AddScoped
(); containerBuilder.AddScoped
(); containerBuilder.AddScoped(typeof(HasDependencyTest4<>)); containerBuilder.AddTransient
(); containerBuilder.AddScoped
(serviceProvider => new WuJing()); containerBuilder.AddSingleton(typeof(GenericServiceTest<>)); containerBuilder.RegisterAssemblyModules(); _container = containerBuilder.Build(); } [Fact] public void Test() { var rootConfig = _container.ResolveService
(); Assert.Throws
(() => _container.ResolveService
()); Assert.Throws
(() => _container.ResolveRequiredService
()); using (var scope = _container.CreateScope()) { var config = scope.ResolveService
(); Assert.Equal(rootConfig, config); var fly1 = scope.ResolveRequiredService
(); var fly2 = scope.ResolveRequiredService
(); Assert.Equal(fly1, fly2); var wukong1 = scope.ResolveRequiredService
(); var wukong2 = scope.ResolveRequiredService
(); Assert.NotEqual(wukong1, wukong2); var wuJing1 = scope.ResolveRequiredService
(); var wuJing2 = scope.ResolveRequiredService
(); Assert.Equal(wuJing1, wuJing2); var s0 = scope.ResolveRequiredService
(); s0.Test(); Assert.Equal(s0._fly, fly1); var s1 = scope.ResolveRequiredService
(); s1.Test(); var s2 = scope.ResolveRequiredService
(); s2.Test(); var s3 = scope.ResolveRequiredService
(); s3.Test(); var s4 = scope.ResolveRequiredService
>(); s4.Test(); using (var innerScope = scope.CreateScope()) { var config2 = innerScope.ResolveRequiredService
(); Assert.True(rootConfig == config2); var fly3 = innerScope.ResolveRequiredService
(); fly3.Fly(); Assert.NotEqual(fly1, fly3); } var flySvcs = scope.ResolveServices
(); foreach (var f in flySvcs) f.Fly(); } var genericService1 = _container.ResolveRequiredService
>(); genericService1.Test(); var genericService2 = _container.ResolveRequiredService
>(); genericService2.Test(); } public void Dispose() { _container.Dispose(); }}

Reference

转载地址:http://uakki.baihongyu.com/

你可能感兴趣的文章
DB2 配置
查看>>
DB2 CHNGPGS_THRES 参数
查看>>
DB2安全性概述
查看>>
DB2 用户管理
查看>>
DB2 脚本
查看>>
DB2 锁升级失败将引起死锁
查看>>
遇到问题该如何解决
查看>>
[第21课] 二项分布3
查看>>
[第22课] 二项分布4
查看>>
Pandas 筛选数据
查看>>
Pandas 复合索引
查看>>
[第23课] 期望值E(X)
查看>>
[第24课] 二项分布的期望值
查看>>
Pandas 处理 NaN
查看>>
Pandas 分组统计
查看>>
Pandas 多 DataFrame联接
查看>>
Sybase 系列文章目录
查看>>
SQLServer
查看>>
Hibernate 通过 Hibernate 访问数据库
查看>>
java面试题
查看>>