ABP 模块系统源码学习:启动时模块是如何加载和排序的
从入口看起AbpApplicationFactory.CreateusingvarappAbpApplicationFactory.CreateBusinessModule(options{options.UseAutofac();});app.Initialize();这行代码的背后发生了什么直接看源码AbpApplicationFactory.cspublicstaticIAbpApplicationWithInternalServiceProviderCreateTStartupModule(ActionAbpApplicationCreationOptions?optionsActionnull){returnnewAbpApplicationWithInternalServiceProvider(typeof(TStartupModule),optionsAction);}它创建了AbpApplicationWithInternalServiceProvider这个类在构造时做了两件关键的事创建ModuleLoader并调用LoadModules加载所有模块按拓扑排序确定模块初始化顺序深度解析 ModuleLoader.LoadModules源码位于framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs核心逻辑只有三行publicIAbpModuleDescriptor[]LoadModules(IServiceCollectionservices,TypestartupModuleType,PlugInSourceListplugInSources){varmodulesGetDescriptors(services,startupModuleType,plugInSources);// 1. 发现所有模块modulesSortByDependency(modules,startupModuleType);// 2. 拓扑排序returnmodules.ToArray();// 3. 返回有序列表}第一步递归发现GetDescriptors内部分两步FillModules——从入口模块开始递归查找所有[DependsOn]依赖// AbpModuleHelper.csprivatestaticvoidAddModuleAndDependenciesRecursively(ListTypemoduleTypes,TypemoduleType,...){moduleTypes.Add(moduleType);foreach(vardependedModuleTypeinFindDependedModuleTypes(moduleType)){AddModuleAndDependenciesRecursively(moduleTypes,dependedModuleType,...);}}FindDependedModuleTypes通过反射读取当前类上的所有[DependsOn]属性publicstaticListTypeFindDependedModuleTypes(TypemoduleType){vardependencyDescriptorsmoduleType.GetCustomAttributes().OfTypeIDependedTypesProvider();foreach(vardescriptorindependencyDescriptors){dependencies.AddIfNotContains(descriptor.GetDependedTypes());}}这意味着不仅[DependsOn]会被识别任何实现了IDependedTypesProvider的自定义属性都能用来声明依赖。第二步拓扑排序protectedvirtualListIAbpModuleDescriptorSortByDependency(ListIAbpModuleDescriptormodules,TypestartupModuleType){varsortedModulesmodules.SortByDependencies(mm.Dependencies);sortedModules.MoveItem(mm.TypestartupModuleType,modules.Count-1);returnsortedModules;}这里使用了SortByDependencies扩展方法来自 Volo.Abp.Core 的工具类是一个标准的拓扑排序实现。排序后入口模块被移到最后一位保证它最后初始化。如果在模块依赖图中存在循环依赖拓扑排序会抛出异常——这在启动时就能发现不会让问题带到运行时。第三步创建模块实例protectedvirtualIAbpModuleCreateAndRegisterModule(IServiceCollectionservices,TypemoduleType){varmodule(IAbpModule)Activator.CreateInstance(moduleType)!;services.AddSingleton(moduleType,module);// 每个模块以 Singleton 注册到 DIreturnmodule;}每个模块实例被注册为 Singleton这意味着模块在整个应用生命周期中只创建一次。生命周期钩子的调用顺序模块加载完毕后调用Initialize进入生命周期阶段。在AbpApplicationBase.cs中阶段 1ConfigureServices for each module in sortedModules: module.Instance.PreConfigureServices(context) for each module in sortedModules: module.Instance.ConfigureServices(context) for each module in sortedModules: module.Instance.PostConfigureServices(context) 阶段 2构建 IServiceProvider 阶段 3OnApplicationInitialization for each module in sortedModules: module.Instance.OnPreApplicationInitialization(context) module.Instance.OnApplicationInitialization(context) module.Instance.OnPostApplicationInitialization(context)注意三个阶段都按排序后的顺序执行入口模块永远在最后。实战要点1. 模块不可循环依赖如果模块 A 依赖 BB 又依赖 A启动时直接抛出AbpException。这比运行时发现要好得多。2. AdditionalAssembly 的用途除了[DependsOn]还有[AdditionalAssembly]属性。它不声明依赖只是告诉框架这个模块的程序集也加载进来。用于解决模块类在另一个程序集中的场景。3. 模块实例是 Singleton模块中定义的状态在应用生命周期内保持。不要在模块中存储请求级别的数据。4. PreConfigureServices 的应用PreConfigureServices可以用于设置默认选项让其他模块在ConfigureServices中可以覆盖publicoverridevoidPreConfigureServices(ServiceConfigurationContextcontext){// 设置默认值允许下游模块覆盖context.Services.AddSingleton(newDefaultOptions{...});}验证结果运行练习示例输出清晰展示了顺序[LoggingModule] ConfigureServices ← 被依赖的模块先执行 [DataAccessModule] ConfigureServices [BusinessModule] ConfigureServices ← 入口模块最后执行即使打乱[DependsOn]的书写顺序输出顺序不变。原因就是SortByDependencies的拓扑排序保证了依赖顺序和代码中的书写顺序无关。

相关新闻

海淀科创新政解读:硬科技、生态连接与评价体系变革

海淀科创新政解读:硬科技、生态连接与评价体系变革

1. 从“海淀放大招”看区域科创政策的底层逻辑最近,海淀区发布的一系列科创政策在圈内引起了不小的讨论。90亿的资金盘子,加上近30条具体措施,这显然不是一次常规的政策微调,而是一次系统性的战略升级。作为一名长期关注科技产业与…

2026/8/3 18:21:43 阅读更多 →
ESP8266 AT命令无响应排查与WiFi模块开发实战指南

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

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

2026/8/4 1:05:50 阅读更多 →
PCB布线实战指南:从信号完整性到生产文件的完整设计流程

PCB布线实战指南:从信号完整性到生产文件的完整设计流程

1. 项目概述:一份来自实战的PCB布线经验沉淀做硬件设计,尤其是画PCB,时间久了总会攒下一些“私货”。这些“私货”不是某个具体的电路图,而是一套经过无数次调试、改版、甚至量产验证后,沉淀下来的布线习惯、规则和“肌…

2026/8/2 3:28:44 阅读更多 →

最新新闻

Clangd vs 传统IDE:C++开发工具2024实测对比与选择指南

Clangd vs 传统IDE:C++开发工具2024实测对比与选择指南

1. 项目概述:为什么我们要重新审视C开发工具? 作为一名在C领域摸爬滚打了十多年的老码农,我经历过从Visual Studio 6.0到如今各种现代化工具的变迁。最近几年,一个名为Clangd的语言服务器协议(LSP)实现&…

2026/8/4 8:12:23 阅读更多 →
Flutter三方库鸿蒙适配实战:以annas_archive_api为例

Flutter三方库鸿蒙适配实战:以annas_archive_api为例

1. 项目背景与核心价值 Flutter开发者最近在跨平台开发中遇到一个关键挑战:如何让现有Flutter生态的三方库无缝适配鸿蒙系统。annas_archive_api作为一个专注于全球影印资源和学术文献检索的Flutter库,其鸿蒙化适配具有典型意义。这个库的核心功能包括&a…

2026/8/4 8:12:23 阅读更多 →
Kimi K3 开放权重后,我更确定:AI 编程的瓶颈已经不是模型

Kimi K3 开放权重后,我更确定:AI 编程的瓶颈已经不是模型

2.8 万亿参数、原生多模态、百万 Token 上下文、面向长程 Coding——Kimi K3 的权重和技术报告开放后,很多开发者的第一反应是:终于可以换一个更强的模型了。 但如果你已经做过一次真实的 AI 项目,可能会有另一个更扎心的判断:模型…

2026/8/4 8:12:23 阅读更多 →
QCustomPlot使用例子

QCustomPlot使用例子

背景: 处理海量波形数据(如录波分析)时,核心痛点在于“文件读取慢”、“内存易溢出”以及“UI渲染卡顿”。环境安装与配置 官网:https://www.qcustomplot.com/index.php/QCustomPlot可直接从官网下载,在工程中引入.h .…

2026/8/4 8:12:23 阅读更多 →
基于 YOLOv8 的垃圾分类识别系统(全套源码+数据集)

基于 YOLOv8 的垃圾分类识别系统(全套源码+数据集)

基于 YOLOv8 目标检测模型 PyQt6 桌面端应用的垃圾分类识别系统,覆盖数据集构建、模型训练调优、系统集成开发的完整深度学习工程流程。 开发日期:2026年 目录 项目概述数据集说明深度学习开发流程训练参数训练指标与结果可视化图表说明系统功能技术栈…

2026/8/4 8:12:23 阅读更多 →
饱受电磁干扰困扰?Versatile Link光纤组件提供新思路

饱受电磁干扰困扰?Versatile Link光纤组件提供新思路

一、为什么选择 Versatile Link 光纤链路? 随着工业 4.0、智能制造、5G 光通信的快速发展,传统铜缆在高速、长距离、强干扰环境下的短板愈发明显——信号衰减、EMI/RFI 干扰、接地环路、电压击穿等问题屡见不鲜。 Versatile Link 系列 应运而生。作为一款…

2026/8/4 8:11:22 阅读更多 →

日新闻

AI Agent白手起家26: 使用标准事件驱动大模型实践

AI Agent白手起家26: 使用标准事件驱动大模型实践

纲要 练习目标:掌握大模型标准事件的调用回顾 LangChain 中的核心标准事件 invokestreambatchastream_eventswith_structured_output 环境准备实战代码:多种事件调用对比 同步调用与流式输出批量处理异步事件流监听结构化输出 运行说明与预期结果总结与扩…

2026/8/4 0:00:40 阅读更多 →
dealsea是什么?跨境卖家必知的美国deal站入门指南

dealsea是什么?跨境卖家必知的美国deal站入门指南

说实话,第一次听说美国这个老牌折扣网站的跨境卖家,十个有八个会问同一个问题:这个平台到底是干嘛的?我见过一个做家居出口的朋友,他在亚马逊上月销二十万美金,却从来没用过它。我给他看了首页——一屏一屏…

2026/8/4 0:01:40 阅读更多 →
清华大学重磅EST:植物自导电闪蒸焦耳热600°C/2600°C两步法!稀土超积累植物秒级转化为CeO₂-石墨烯电催化剂!

清华大学重磅EST:植物自导电闪蒸焦耳热600°C/2600°C两步法!稀土超积累植物秒级转化为CeO₂-石墨烯电催化剂!

通讯作者:邓兵、刘建国通讯单位:清华大学DOI:https://doi.org/10.1021/acs.est.6c00603研究背景稀土元素(REEs)是清洁能源技术与电子器件不可或缺的核心原料,然而传统提取方式依赖能耗高、排放大的采矿与强…

2026/8/4 0:01:40 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/3 4:58:13 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/3 1:53:31 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/4 5:26:40 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/3 13:07:03 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/3 5:19:38 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/3 8:27:36 阅读更多 →