发布时间:2026/8/2 3:28:39
ABP 依赖注入源码解读:约定注册器是如何自动扫描和注册服务的 传统 vs ABP传统方式services.AddScopedIUserService,UserService();services.AddTransientIEmailService,EmailService();ABP 方式publicclassUserService:IUserService,ITransientDependency{}背后的原理是什么直接看DefaultConventionalRegistrar.cs源码。源码位置framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DefaultConventionalRegistrar.cs约定注册的核心流程publicoverridevoidAddType(IServiceCollectionservices,Typetype){// 1. 检查是否禁用了约定注册if(IsConventionalRegistrationDisabled(type))return;// 2. 获取生命周期vardependencyAttributeGetDependencyAttributeOrNull(type);varlifeTimeGetLifeTimeOrNull(type,dependencyAttribute);if(lifeTimenull)return;// 没实现标记接口不注册// 3. 获取暴露的服务类型注册为哪个接口varexposedServiceAndKeyedServiceTypesGetExposedKeyedServiceTypes(type).Concat(GetExposedServiceTypes(type).Select(tnewServiceIdentifier(t))).ToList();// 4. 触发暴露事件其他模块可以修改TriggerServiceExposing(services,type,exposedServiceAndKeyedServiceTypes);// 5. 逐一添加到 DI 容器foreach(varexposedServiceTypeinexposedServiceAndKeyedServiceTypes){varserviceDescriptorCreateServiceDescriptor(type,...,lifeTime);services.Add(serviceDescriptor);}}第一步生命周期判定GetLifeTimeOrNull的优先级protectedvirtualServiceLifetime?GetLifeTimeOrNull(Typetype,DependencyAttribute?dependencyAttribute){returndependencyAttribute?.Lifetime// 1. [Dependency] 属性指定??GetServiceLifetimeFromClassHierarchy(type)// 2. 标记接口??GetDefaultLifeTimeOrNull(type);// 3. 默认值null 不注册}GetServiceLifetimeFromClassHierarchy检查类的继承链if(typeof(ITransientDependency).IsAssignableFrom(type))returnServiceLifetime.Transient;if(typeof(ISingletonDependency).IsAssignableFrom(type))returnServiceLifetime.Singleton;if(typeof(IScopedDependency).IsAssignableFrom(type))returnServiceLifetime.Scoped;三个标记接口都是空接口没有任何方法纯标记用途publicinterfaceITransientDependency{}// 空接口publicinterfaceISingletonDependency{}// 空接口publicinterfaceIScopedDependency{}// 空接口第二步暴露服务类型判定ExposedServiceExplorer.GetExposedServices的默认逻辑// 1. 有 [ExposeServices] → 用属性指定的类型// 2. 没有 → 按约定推断// 遍历类实现的所有接口// 接口名去掉 I 前缀剩下的跟类名比较// 如果类名以它结尾不区分大小写则匹配比如publicclassProductService:IProductService,ITransientDependency// IProductService → 去掉 I → ProductService → 类名 ProductService 以 ProductService 结尾 → 匹配// 相当于 [ExposeServices(typeof(IProductService))]第三步ServiceDesciptor 注册最后调用services.Add(serviceDescriptor)但还有两个变体if(dependencyAttribute?.ReplaceServicestrue)services.Replace(serviceDescriptor);// 替换已有注册elseif(dependencyAttribute?.TryRegistertrue)services.TryAdd(serviceDescriptor);// 不存在时才注册elseservices.Add(serviceDescriptor);// 默认直接注册启动时扫描谁ABP 启动时每个模块的ConfigureServices阶段会调用context.Services.AddAssemblyOfTModule();这个方法扫描当前模块所在程序集的所有公开类型对每个类型执行DefaultConventionalRegistrar.AddType。所以一个类只要在模块的程序集中、实现了标记接口就会被自动注册。实战如何排查注册问题如果发现IServiceProvider.GetServiceT()返回 null按这个顺序排查检查类是否在模块的程序集中在哪个项目那个项目被引用了检查类是否实现了标记接口ITransientDependency/ISingletonDependency/IScopedDependency检查是否写了[DisableConventionalRegistration]检查生命周期选择是否正确对比总结// 方式 1标记接口最常用publicclassMyService:ITransientDependency{}// 方式 2标记接口 显示的暴露接口[ExposeServices(typeof(IUserService))]publicclassUserService:IUserService,ITransientDependency{}// 方式 3[Dependency] 精细控制[Dependency(ReplaceServicestrue)]publicclassMockService:IRealService,ITransientDependency{}// 方式 4禁用自动注册手动管理[DisableConventionalRegistration]publicclassHelperService{}// 需要手动 services.AddSingletonHelperService()

相关新闻

2026/8/2 3:28:39

2026年毕业生黑科技榜单9款AI论文写作软件实测!

前言:AI 写论文乱象频发,实测 8 款工具理清适配边界 每到毕业季,本科生、硕博生都会扎堆寻找 AI 论文辅助工具,市面上各类写作软件层出不穷,但普遍存在几类硬伤:虚假参考文献、无法匹配本校格式、不支持公式…

2026/8/2 3:28:39

4英寸720x720高PPI方形LCD驱动全解析:从硬件选型到软件实战

1. 项目概述:一块“非主流”方形高分辨率屏幕的深度探索最近在捣鼓一个桌面小摆件项目,想找一块显示效果细腻、尺寸又足够小巧的屏幕。市面上常见的3.5寸、5寸屏大多是480x320或800x480的分辨率,颗粒感在所难免。直到我发现了“4inch 720x720…

2026/8/2 3:28:39

ESP8266 AT命令无响应排查与WiFi模块开发实战指南

第一次拿到 ESP8266 模块时,我把它插上 USB 转串口线,打开串口调试助手,敲下AT然后期待地按下回车——结果什么反应都没有。屏幕上一片空白,模块上的蓝色指示灯安静地亮着,仿佛在嘲笑我的无知。这不是一个简单的“串口…

2026/8/2 4:48:43

CytoTRACE:基于基因表达多样性的单细胞分化潜能评估算法详解

1. 从细胞异质性到发育轨迹:为什么我们需要CytoTRACE?在单细胞转录组数据分析里,我们拿到手的往往是一个个细胞的基因表达矩阵。这些细胞看起来是“一锅粥”,但实际上,它们可能处于不同的分化阶段、不同的细胞周期&…

2026/8/2 4:48:43

Unity口型动画实战:从LipSync原理到SALSA插件高效配置

1. 项目概述:为什么需要专业的口型动画方案?在Unity中制作角色对话动画,尤其是口型同步,长期以来都是让开发者头疼的环节。早期很多项目要么采用手动K帧,一个音节一个音节地去调整嘴型,耗时耗力且效果生硬&…

2026/8/2 4:48:43

Node-RED全局变量持久化存储方案:从文件到数据库的实战指南

1. 项目概述:为什么我们需要全局变量存储?在Node-RED的日常开发中,我们经常会遇到一个看似简单却让人头疼的问题:如何让一个变量在流程重启后依然存在?比如,你做了一个智能家居的自动化控制面板&#xff0c…

2026/8/2 4:48:43

最左前缀匹配原则

[[MySQL]] 最左前缀匹配原则详解 1. 什么是最左前缀匹配原则? 最左前缀匹配原则是 MySQL 联合索引(组合索引) 的重要规则。 简单来说:当使用联合索引查询时,MySQL 会从索引的最左列开始匹配,不能跳过中间列…

2026/8/2 4:48:43

GIME2027西北(兰州)煤炭与煤化工业展览会,5月举办

GIME甘肃煤博会:丝路枢纽,链接西北能源新未来, GIME2027西北(兰州)煤炭与煤化工业展览会 Northwest Coal and Coal Chemical Industry Exhibition 举办时间:2027年5月14-16日 使用展馆:兰州丝路…

2026/8/2 4:43:43

scikit-learn安装全攻略:从环境配置到避坑指南

1. 项目概述:从一次恼人的安装错误说起如果你刚开始接触Python机器学习,那么scikit-learn(简称sklearn)几乎是你绕不开的第一个重量级库。它封装了从数据预处理、特征工程到模型训练、评估的完整流程,API设计优雅统一&…

2026/8/2 0:02:18

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/2 0:02:18

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/2 1:52:02

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/1 0:03:49

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/1 0:03:49

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…