最新要闻
- 一加Ace 2V 12+256G起步行业罕见:友商还在搞8+128卡价位的版本
- 实时:Redmi Note 12 Pro极速版12+256G到手1999元:开机就是MIUI 14
- 造车新势力2月交付量出炉:理想、蔚来、哪吒破万 零跑压力大
- 【全球速看料】厦门征求意见!过马路玩手机或将罚款50元 你支持吗?
- 世界快看:东风概念飞行汽车外观曝光!“鸥翼门”相当炫酷
- 【当前热闻】2018巴彦淖尔国际马拉松
- 环球焦点!胡明轩:平时杜导叫我和徐杰一起训练 要求我们承担起更多责任
- 环球聚焦:委员建议隔周三休成热搜第一 网友吵翻 专家:很难行得通
- 今日热闻!Model 2明天发?这款15万的特斯拉便宜车:马斯克已经说了17年
- 风语筑(603466):上海风语筑文化科技股份有限公司关于股东权益变动比例超过1%的提示性公告
- 天天观察:希望工程发文感谢《原神》玩家 5天9万多人捐赠240万元
- 世界聚焦:“刺客”又来了!网友称买到1600元一斤话梅:每颗至少20元
- “窄边教科书”上新!戴尔XPS15 9530发布:13代酷睿+RTX 40配8TB SSD
- 环球微动态丨孟菲斯动物园发大熊猫丫丫新动态 网友:尽快回国!
- 曝苹果屏下Face ID技术有缺憾:2026年才会趋于完美
- 信息:可取代eSIM:更完美的iSIM卡来了
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
热消息:Fireasy3 揭秘 -- 万物伊始(依赖注入与服务发现)
最近在忙于 Fireasy 的重构,3.x 抛弃了 .Net Framework时代的一些思想和模式,紧密拥抱 .Net Core,但它的思想仍然是开放性和灵活性。今天我主要来说说依赖注入与服务发现。
【资料图】
.Net Core 有自己的一套依赖注入,它的容器暴露给 IServiceCollection,通过在里面放入一些单例(Singleton)、瞬时(Transient)、作用域(Scoped)的一些服务描述(服务与实现的关系映射),这一部分我就不再细说了。
当然,一般常用的方式是,通过 AddSingleton、AddTransient 和 AddScoped 方法往容器里面加,但如果是依赖比较多的情况下(比如业务服务类),那你可能会经常忘了写这一部分代码了,而且也很难于维护。如常见的方式:
void ConfigureServices(IServiceCollection services){ services.AddTransient(); services.AddTransient (); services.AddTransient (); services.AddTransient (); //....... services.AddTransient (); services.AddTransient ();}
有没有更简便更容易维护的方式呢?答案是当然有!
在 Fireasy,我们定义了三个服务接口,分别是ISingletonService、ITransientService 和IScopedService,这三个类只是一个标识,没有具体的方法和属性。使用需要注入的类实现此接口,如下:
public class DeptmentService : IDeptmentService, ITransientService{ // ......}public class DataRoleHelper : IDataRoleHelper, ISingletonService{ // ......}
好了,你只需在 ConfigureServices 里添加上这么一行代码,就能实现依赖注入:
void ConfigureServices(IServiceCollection services){ services.AddFireasy();}
现在开始步入正题了,来看看 AddFireasy 是如何工作的。
IServiceDiscoverer 是用于服务发现的接口,它的默认实现是DefaultServiceDiscoverer。如下:
public static SetupBuilder AddFireasy(this IServiceCollection services, Action? configure = null) { var options = new SetupOptions(); configure?.Invoke(options); var builder = new SetupBuilder(services, options); var discoverer = options.DiscoverOptions.DiscovererFactory == null ? new DefaultServiceDiscoverer(services, options.DiscoverOptions) : options.DiscoverOptions.DiscovererFactory(services, options.DiscoverOptions); if (discoverer != null) { services.AddSingleton (discoverer); } return builder; }
入口方法是 DiscoverServices,它会遍列程序目录下的所有程序集文件(*.dll),这里有程序集过滤器,你可以自己定义过滤规则。如下:
////// 发现工作目录中所有程序集中的依赖类型。 /// /// 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); } }
方法 DiscoverServices 用于对单个程序集进行服务发现并进行注册,这里同样也有类型过滤器,如下:
////// 发现程序集中的所有依赖类型。 /// /// /// private void DiscoverServices(IServiceCollection services, Assembly assembly) { foreach (var type in assembly.GetExportedTypes()) { if (_options?.TypeFilters?.Any(s => s.IsFilter(assembly, type)) == true) { continue; } if (_options?.TypeFilterPredicates?.Any(s => s(assembly, type)) == true) { continue; } ServiceLifetime? lifetime; var interfaceTypes = type.GetDirectImplementInterfaces().ToArray(); //如果使用标注 if (type.IsDefined(typeof(ServiceRegisterAttribute))) { lifetime = type.GetCustomAttribute()!.Lifetime; } else { lifetime = GetLifetimeFromType(type); } if (lifetime == null) { continue; } if (interfaceTypes.Length > 0) { interfaceTypes.ForEach(s => AddService(services, s, type, (ServiceLifetime)lifetime)); } else { AddService(services, type, type, (ServiceLifetime)lifetime); } } } private ServiceLifetime? GetLifetimeFromType(Type type) { if (typeof(ISingletonService).IsAssignableFrom(type)) { return ServiceLifetime.Singleton; } else if (typeof(ITransientService).IsAssignableFrom(type)) { return ServiceLifetime.Transient; } else if (typeof(IScopedService).IsAssignableFrom(type)) { return ServiceLifetime.Scoped; } return null; } private ServiceDescriptor AddService(IServiceCollection services, Type serviceType, Type implType, ServiceLifetime lifetime) { var descriptor = ServiceDescriptor.Describe(serviceType, implType, lifetime); _descriptors.Add(descriptor); services.Add(descriptor); return descriptor; }
从上面的代码中可看出,通过在程序集内部查找实现了ISingletonService、ITransientService 或 IScopedService 的类,并将它们添加到 services 中,这样就完成了开篇提到的工作。
这里还出现了一个ServiceRegisterAttribute,它在不实现以上三个接口的情况下,通过标注 Lifetime 生命周期来进行注册,一样达到了目的。
接下来做几个简单的单元测试。
单例测试:
////// 测试单例服务 /// [TestMethod] public void TestSingletonService() { var services = new ServiceCollection(); var builder = services.AddFireasy(); var serviceProvider = services.BuildServiceProvider(); var service1 = serviceProvider.GetService(); var service2 = serviceProvider.GetService (); Assert.IsNotNull(service1); Assert.IsNotNull(service2); //两对象的id应相等 Assert.AreEqual(service1.Id, service2.Id); } public interface ITestSingletonService { Guid Id { get; } void Test(); } public class TestSingletonServiceImpl : ITestSingletonService, ISingletonService { public TestSingletonServiceImpl() { Id = Guid.NewGuid(); } public Guid Id { get; } public void Test() => Console.WriteLine("Hello TestSingletonService!"); }
瞬时测试:
////// 测试瞬时服务 /// [TestMethod] public void TestTransientService() { var services = new ServiceCollection(); var builder = services.AddFireasy(); var serviceProvider = services.BuildServiceProvider(); var service1 = serviceProvider.GetService(); var service2 = serviceProvider.GetService (); Assert.IsNotNull(service1); Assert.IsNotNull(service2); //两对象的id应不相等 Assert.AreNotEqual(service1.Id, service2.Id); } public interface ITestTransientService { Guid Id { get; } void Test(); } public class TestTransientServiceImpl : ITestTransientService, ITransientService { public TestTransientServiceImpl() { Id = Guid.NewGuid(); } public Guid Id { get; } public void Test() => Console.WriteLine("Hello TestTransientService!"); }
作用域测试:
////// 测试作用域服务 /// [TestMethod] public void TestScopedService() { var services = new ServiceCollection(); var builder = services.AddFireasy(); var serviceProvider = services.BuildServiceProvider(); Guid id1, id2; //作用域1 using (var scope1 = serviceProvider.CreateScope()) { var service1 = scope1.ServiceProvider.GetService(); var service2 = scope1.ServiceProvider.GetService (); Assert.IsNotNull(service1); Assert.IsNotNull(service2); //两对象的id应相等 Assert.AreEqual(service1.Id, service2.Id); id1 = service1.Id; } //作用域2 using (var scope2 = serviceProvider.CreateScope()) { var service1 = scope2.ServiceProvider.GetService (); var service2 = scope2.ServiceProvider.GetService (); Assert.IsNotNull(service1); Assert.IsNotNull(service2); //两对象的id应相等 Assert.AreEqual(service1.Id, service2.Id); id2 = service1.Id; } //两次scoped的id应不相等 Assert.AreNotEqual(id1, id2); } public interface ITestScopedService { Guid Id { get; } void Test(); } public class TestScopedServiceImpl : ITestScopedService, IScopedService { public TestScopedServiceImpl() { Id = Guid.NewGuid(); } public Guid Id { get; } public void Test() => Console.WriteLine("Hello TestScopedService!"); }
可见,不需要显式 Add 也能将大量的服务类注入到容器中,不仅节省了大量的时间和代码,更是提高了程序的可维护性。
最后,奉上 Fireasy 3 的开源地址:https://gitee.com/faib920/fireasy3,欢迎大家前来捧场。
本文相关代码请参考https://gitee.com/faib920/fireasy3/src/libraries/Fireasy.Common/DependencyInjection下的相关文件。
-
环球新动态:Spark系列 - (5) Spark Shuffle
目前已经更新完《Java并发编程》,《JVM性能优化》,《Spring核心知识》《Docker教程》和《Spark基础知识...
来源: -
热消息:Fireasy3 揭秘 -- 万物伊始(依赖注入与服务发现)
最近在忙于Fireasy的重构,3 x抛弃了 NetFramework& 160;时代的一些思想和模式,紧密拥抱 NetCore,...
来源: 环球新动态:Spark系列 - (5) Spark Shuffle
热消息:Fireasy3 揭秘 -- 万物伊始(依赖注入与服务发现)
全球信息:英语四级阅读技巧
一加Ace 2V 12+256G起步行业罕见:友商还在搞8+128卡价位的版本
实时:Redmi Note 12 Pro极速版12+256G到手1999元:开机就是MIUI 14
造车新势力2月交付量出炉:理想、蔚来、哪吒破万 零跑压力大
【全球速看料】厦门征求意见!过马路玩手机或将罚款50元 你支持吗?
世界快看:东风概念飞行汽车外观曝光!“鸥翼门”相当炫酷
【当前热闻】2018巴彦淖尔国际马拉松
环球焦点!胡明轩:平时杜导叫我和徐杰一起训练 要求我们承担起更多责任
世界快讯:makefile
基于alpine基础镜像构建jdk镜像以及tomcat镜像及业务构建
Linux极简入门系列(六):其它补充
CSS全局关键字
环球聚焦:委员建议隔周三休成热搜第一 网友吵翻 专家:很难行得通
今日热闻!Model 2明天发?这款15万的特斯拉便宜车:马斯克已经说了17年
环球新消息丨LOJ 3276 JOISC 2020 Day2 遗迹 题解 (计数DP)
环球快资讯:MySQL学习笔记-多表查询(上)
当前视讯!量化交易基础 - 011 - 样本外检验
风语筑(603466):上海风语筑文化科技股份有限公司关于股东权益变动比例超过1%的提示性公告
天天观察:希望工程发文感谢《原神》玩家 5天9万多人捐赠240万元
世界聚焦:“刺客”又来了!网友称买到1600元一斤话梅:每颗至少20元
“窄边教科书”上新!戴尔XPS15 9530发布:13代酷睿+RTX 40配8TB SSD
环球微动态丨孟菲斯动物园发大熊猫丫丫新动态 网友:尽快回国!
曝苹果屏下Face ID技术有缺憾:2026年才会趋于完美
C++ STL学习笔记-C++ STL基础
焦点讯息:4-Ribbon负载均衡
信息:可取代eSIM:更完美的iSIM卡来了
二月浏览器大战结果出炉:微软Edge用户数不升反降
头条:《王者荣耀》干将莫邪画中仙皮肤公布:中国古风莫邪绝美
环球微头条丨k8s之list-watch机制、节点调度以及亲和性
全球速讯:记录--虚拟滚动探索与封装
天天百事通!(数据库系统概论|王珊)第七章数据库设计-第四节:逻辑结构设计
焦点热议:Cesium 几何体贴模型 sampleHeight(二十二)
环球滚动:苏富比春拍上海预展即将开展,近150件藏品由谁保驾护航?
全球即时看!蔚来2022年财报公布:全年营收492亿元 同比大涨36%
天天资讯:建议元宵节放假1天:提升人民幸福指数
环球通讯!超19万辆!比亚迪2月新能源销量公布:暴打新势力全家
全球微头条丨2023五一档电影增至五部!哪部对你吸引力更大?
热点!Cesium Transform(二十)
世界速讯:第124篇: 期约Promise
怎么登录新浪微博网页版_如何登陆新浪微博
环球快报:刹车变硬踩不动遭车主集体投诉 铃木召回超7.8万辆汽车
【独家】好利来创始人之子回应开劳斯莱斯摆摊:没想博眼球
天天快播:AI小姐姐比真人还好看? N卡又抓到风口:8GB显存稳定绘图 首选RTX30/40系
春丽今天55岁了!网友:Coser我永远只服成龙大哥
速讯:URLDNS链分析
认识数据标签
每日速递:Python识别图形验证码实战项目
全球播报:记一次CPU占用持续上升问题排查(Nacos动态路由引起)
iOS应用发布ITMS-90704错误解决
荣耀“青海湖技术”揭晓:荣耀Magic5系列全球首发硅碳负极技术
国内专属!新款国产特斯拉Model Y升级悬架:终于不颠了
天天热门:功耗开放470W!影驰名人堂RTX 4080真是生猛
每日热讯!又一游戏成功“入奥”:育碧《舞力全开》入选2023年奥林匹克电子竞技项目
天天头条:女子幼儿园收童子尿煮鸡蛋 吃着香是浙江当地非遗:网友直呼酸爽
今日热闻!中国通才教育:已针对首次公开发售相关指控开展独立调查,将继续停牌
全球百事通!为什么95%的Java程序员人,都是用不好Synchronized?
每日时讯!Python教程:类的派生
你有“ChatGPT综合征”吗:想搞钱,或是失业焦虑?
Python教程:类的继承,什么是继承
加点广告怎么了 爱奇艺新专利可在弹幕中显示广告
环球动态:狂飙8000MHz!朗科Z RGB DDR5-8000 16GB电镀银内存图赏
每日短讯:1:1复刻仿生人手 现实版《西部世界》公司众筹开启
全球头条:5G是高铁 6G就是飞机!工信部:全面推进6G技术研发
焦点热文:公司丢货要求全体员工均摊1万赔款:新员工拒赔反被怀疑偷东西
天天观察:如何在Ubuntu上安装Nextcloud(适用于树莓派上的Ubuntu)
每日播报!Pod 进阶
每日快看:Zabbix“专家坐诊”第183期问答汇总
Spring中Bean的加载方式~
什么是Markdown
当前报道:纬德信息(688171)3月1日主力资金净买入105.72万元
旅俄大熊猫画风突变体重狂飙40公斤:摸爬滚打样样精通
百事通!特斯拉Model 2被曝成本大降37% 比丰田卡罗拉还低
世界短讯!打赢了!科比坠机照片泄露案其遗孀获赔2885万美元
天天热头条丨惊险一幕:女子用火车站自动扶梯运行李 把下面男子砸骨折
【全球速看料】玩游戏需自备爆米花:《最终幻想16》主线过场动画超11小时
当前快看:1000亿数据、30W级qps如何架构?来一个天花板案例
3-Eureka注册中心
天天精选!【验证码逆向专栏】某验三代、四代一键通过模式逆向分析
当前信息:索泰RTX 4090月白深度测试:真孤独求败!A卡没得玩了
网友晒视频广州一特斯拉在停车场连撞多车 司机下车就跑:又踩错了吗
当前看点!设计时速100公里!上海苏州互通地铁今起试跑:苏州坐地铁直达
环球资讯:韦达定理
全球播报:轻松玩转Makefile | 基础用法
医院拍CT有位患者叫熊猫 结果竟是真熊猫:网友祝福“国宝”尽快好起来
丰田拆完一辆特斯拉Model Y后被震撼了 高管惊叹:我们远远落后
全球新动态:火爆全网的AI小姐姐模型重新上线 作者:画什么图后果自负
【全球热闻】大厂年薪30万95后女生转行卖快餐:直言脱离公司KPI太快乐了
当前观察:《暗黑破坏神4》玩家打怪时 不会出现天量伤害数值
世界今热点:通用电梯:目前产能在满足履行轨道交通项目合同需求的同时,不会影响公司履行其他客户订单或新接订单的生产需求
环球报道:电脑病毒的介绍与防护_电脑病毒与防护介绍
天天日报丨浅析大促备战过程中出现的fullGc,我们能做什么?
ChunJun 1.16 Release版本即将发布,bug 捉虫活动邀您参与!
一款超级给力的弱网测试神器—Qnet(附视频)
焦点要闻:Vue,小程序开发技术详解
环球即时看!关于React-Router6 (React 路由)
每日简讯:取代马斯克:新CEO接班人浮出水面
健身网红大容量运动杯:富光1.6L顿顿桶29元发车
每日热门:马力超百匹!春风NK800双缸街车发布:46890元起