news 2026/8/2 3:28:23

ABP 依赖注入源码解读:约定注册器是如何自动扫描和注册服务的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ABP 依赖注入源码解读:约定注册器是如何自动扫描和注册服务的

传统 vs ABP

传统方式:

services.AddScoped<IUserService,UserService>();services.AddTransient<IEmailService,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. 获取生命周期vardependencyAttribute=GetDependencyAttributeOrNull(type);varlifeTime=GetLifeTimeOrNull(type,dependencyAttribute);if(lifeTime==null)return;// 没实现标记接口,不注册// 3. 获取暴露的服务类型(注册为哪个接口)varexposedServiceAndKeyedServiceTypes=GetExposedKeyedServiceTypes(type).Concat(GetExposedServiceTypes(type).Select(t=>newServiceIdentifier(t))).ToList();// 4. 触发暴露事件(其他模块可以修改)TriggerServiceExposing(services,type,exposedServiceAndKeyedServiceTypes);// 5. 逐一添加到 DI 容器foreach(varexposedServiceTypeinexposedServiceAndKeyedServiceTypes){varserviceDescriptor=CreateServiceDescriptor(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?.ReplaceServices==true)services.Replace(serviceDescriptor);// 替换已有注册elseif(dependencyAttribute?.TryRegister==true)services.TryAdd(serviceDescriptor);// 不存在时才注册elseservices.Add(serviceDescriptor);// 默认:直接注册

启动时扫描谁?

ABP 启动时,每个模块的ConfigureServices阶段会调用:

context.Services.AddAssemblyOf<TModule>();

这个方法扫描当前模块所在程序集的所有公开类型,对每个类型执行DefaultConventionalRegistrar.AddType。所以一个类只要在模块的程序集中、实现了标记接口,就会被自动注册。

实战:如何排查注册问题

如果发现IServiceProvider.GetService<T>()返回 null,按这个顺序排查:

  1. 检查类是否在模块的程序集中(在哪个项目?那个项目被引用了?)
  2. 检查类是否实现了标记接口(ITransientDependency/ISingletonDependency/IScopedDependency
  3. 检查是否写了[DisableConventionalRegistration]
  4. 检查生命周期选择是否正确

对比总结

// 方式 1:标记接口(最常用)publicclassMyService:ITransientDependency{}// 方式 2:标记接口 + 显示的暴露接口[ExposeServices(typeof(IUserService))]publicclassUserService:IUserService,ITransientDependency{}// 方式 3:[Dependency] 精细控制[Dependency(ReplaceServices=true)]publicclassMockService:IRealService,ITransientDependency{}// 方式 4:禁用自动注册,手动管理[DisableConventionalRegistration]publicclassHelperService{}// 需要手动 services.AddSingleton<HelperService>()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/2 3:27:58

GEO 排名原理与逻辑 —— 基于 AGENT 底层逻辑深度解析

GEO 全称 Generative Engine Optimization&#xff08;生成式引擎优化&#xff09;&#xff0c;区别于传统搜索引擎 SEO 网页排名&#xff0c;GEO 排名决定信息、品牌、服务商在大模型智能问答、AI 搜索结果中的引用次序。很多从业者疑惑&#xff0c;相同检索场景下&#xff0c…

作者头像 李华
网站建设 2026/8/2 3:27:22

投入产出比

投入产出比通常说的投入产出比&#xff1a;&#xff08;净赚金额 投入本金&#xff09; 100%也有&#xff0c;本利和比率&#xff1a;&#xff08;最终总金额 投入本金&#xff09; 100%投入 100 元&#xff0c;赚 10 元&#xff0c;投入产出比为 (100 10) / 100 * 100% &am…

作者头像 李华
网站建设 2026/8/2 3:24:20

单片机毕设项目:射频识别嵌入式小型停车场自动收费装置设计 基于单片机蜂鸣提醒智能停车闸控系统实现(016501)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/8/2 3:21:22

解锁WeMod专业体验:Wand-Enhancer带来的游戏修改新维度

解锁WeMod专业体验&#xff1a;Wand-Enhancer带来的游戏修改新维度 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer 你是否曾在游戏世界中遇到难以逾…

作者头像 李华
网站建设 2026/8/2 3:18:52

上_为什么AI落地缺的不是模型,而是一套让AI看懂业务的世界模型

一、先说一个真事去年底&#xff0c;一家制造企业的领导跟我抱怨&#xff1a;他们花了大价钱上了大模型&#xff0c;想让AI帮忙处理设备告警。结果呢&#xff1f;大模型确实能读懂告警信息&#xff0c;也能用漂亮的话总结出一套处理建议。但一到真正干活——比如该不该自动生成…

作者头像 李华