VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • 动手造轮子:实现一个简单的依赖注入(二) --- 服务注册优化

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

Intro#

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

实现代码#

ServiceContainerBuilder#

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


Copy
public interface IServiceContainerBuilder { IServiceContainerBuilder Add(ServiceDefinition item); IServiceContainerBuilder TryAdd(ServiceDefinition item); IServiceContainer Build(); } public class ServiceContainerBuilder : IServiceContainerBuilder { private readonly List<ServiceDefinition> _services = new List<ServiceDefinition>(); 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 这个类型也可以变成一个内部类了,不必再对外暴露


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

ServiceContainerModule#

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


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

自定义 ServiceContainerModule 使用示例:


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

RegisterAssemblyModules 扩展方法实现如下:


Copy
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<Assembly>().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; }

使用示例#

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


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

Reference#

  • https://github.com/WeihanLi/WeihanLi.Common/tree/dev/src/WeihanLi.Common/DependencyInjection
  • https://www.cnblogs.com/weihanli/p/implement-dependency-injection-01.html
  • https://www.cnblogs.com/weihanli/p/implement-dependency-injection.html
  • https://autofac.org/
  • https://autofac.readthedocs.io/en/latest/register/scanning.html

作者: WeihanLi

出处:https://www.cnblogs.com/weihanli/p/implement-dependency-injection-02.html



相关教程