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

网友投稿 1021 2022-09-11

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

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

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

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 _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 这个类型也可以变成一个内部类了,不必再对外暴露

Copy

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 需要注册的服务

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(GuidIdGenerator.Instance); } }

RegisterAssemblyModules 扩展方法实现如下:

Copy

public static IServiceContainerBuilder RegisterAssemblyModules( [NotNull] this IServiceContainerBuilder serviceContainerBuilder, params Assembly[] assemblies) { #if NET45 // 解决 asp- 在 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; }

使用示例#

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

Copy

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#

https://github.com/WeihanLi/WeihanLi.Common/tree/dev/src/WeihanLi.Common/DependencyInjection

https://cnblogs.com/weihanli/p/implement-dependency-injection-01.html

https://cnblogs.com/weihanli/p/implement-dependency-injection.html

https://autofac.org/

https://autofac.readthedocs.io/en/latest/register/scanning.html

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:windows服务器-远程访问服务器
下一篇:DOS下查看端口占用-netstat -ano
相关文章

 发表评论

暂时没有评论,来抢沙发吧~