动手造*:实现一个简单的依赖注入(二) --- 服务注册优化
动手造*:实现一个简单的依赖注入(二) --- 服务注册优化
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<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
这个类型也可以变成一个内部类了,不必再对外暴露
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
需要注册的服务
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<iidgenerator>(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<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; }
使用示例
使用起来除了注册服务变化了之外,别的地方并没有什么不同,看一下单元测试代码
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
上一篇: linux启动脚本
下一篇: Linux文件的操作及授权