前言
在开发分布式系统时,我们常常会遇到这样的问题:不同模块(如 API 服务、数据采集服务、算法引擎)对基础设施的需求各不相同。API 模块需要完整的数据库、Redis、JWT 认证,而看门狗服务可能只需要 Redis。如何设计一个灵活的初始化架构来应对这种差异?
本文将分享一种基于 .NET 8 的模块化初始化模式。
核心设计
1. 初始化选项类
首先定义一个配置类,用于控制各模块的初始化行为:
public class InitOptions {
public string ModuleName { get; set; } = "app";
public bool InitializeDatabase { get; set; } = true;
public bool InitializeRedis { get; set; } = true;
public bool InitializeJwt { get; set; } = true;
public bool InitializeLog { get; set; } = true;
public bool SyncModelTables { get; set; } = false;
// 容错配置
public bool ContinueOnRedisFail { get; set; } = true;
public bool ContinueOnJwtFail { get; set; } = true;
}
2. 模块自动配置
根据模块名称自动配置初始化选项:
public static bool InitializeAll(IConfiguration configuration, string moduleName = "app") {
var options = new InitOptions { ModuleName = moduleName };
// API 模块:完整初始化
if (moduleName.Equals("Api", StringComparison.OrdinalIgnoreCase)) {
options.InitializeDatabase = true;
options.InitializeRedis = true;
options.InitializeJwt = true;
options.SyncModelTables = true; // 只有 API 负责表结构同步
}
// SoftDog 模块:仅 Redis
else if (moduleName.Equals("SoftDog", StringComparison.OrdinalIgnoreCase)) {
options.InitializeDatabase = false;
options.InitializeRedis = true;
options.InitializeJwt = false;
options.ContinueOnRedisFail = false; // Redis 是必需的
}
// 其他模块:按需配置
else {
options.InitializeDatabase = true;
options.InitializeRedis = true;
options.InitializeJwt = false;
}
return InitializeAll(configuration, options);
}
3. 分步初始化
按优先级顺序执行各模块初始化:
public static bool InitializeAll(IConfiguration configuration, InitOptions options) {
Console.WriteLine($"[初始化] 开始初始化 {options.ModuleName} 模块...");
// 1. 数据库初始化(必需)
if (options.InitializeDatabase) {
if (!DatabaseInit.Initialize(configuration, options.SyncModelTables)) {
return false; // 数据库失败直接退出
}
}
// 2. Redis 初始化(可选容错)
if (options.InitializeRedis) {
if (!RedisInit.Initialize(configuration)) {
if (!options.ContinueOnRedisFail) {
return false;
}
Console.WriteLine("[初始化] ⚠ Redis 失败,但程序继续运行");
}
}
// 3. JWT 初始化
if (options.InitializeJwt) {
JwtInit.Initialize(configuration);
}
return true;
}
4. 优雅关闭
程序退出时按逆序关闭资源:
public static async Task ShutdownAsync() {
// 1. 先关闭应用层(日志缓冲等)
await ApiLogMiddleware.ShutdownAsync();
await LogHelper.ShutdownAsync();
await FileLogWriter.ShutdownAsync();
// 2. 再关闭基础设施层
ConfigExportService.Shutdown();
DatabaseBackupService.Shutdown();
RedisInit.Shutdown();
}
程序入口示例
public class Program {
private static readonly CancellationTokenSource s_cts = new();
public static void Main(string[] args) {
// 注册退出事件
Console.CancelKeyPress += (s, e) => {
e.Cancel = true;
s_cts.Cancel();
};
// 加载配置
var configuration = ConfigurationInit.LoadConfiguration();
// 初始化所有组件
if (!AppInitializer.InitializeAll(configuration, "Api")) {
Console.WriteLine("[Api] 初始化失败,程序退出");
return;
}
// 启动服务
WebServerInit.StartWebServer(configuration, serverUrl, s_cts.Token);
// 清理资源
AppInitializer.ShutdownAsync().GetAwaiter().GetResult();
}
}
设计优势
- 灵活配置:每个模块可以按需选择初始化哪些组件
- 容错机制:非关键组件失败可以选择继续运行
- 统一入口:所有初始化逻辑集中管理,便于维护
- 优雅关闭:确保资源按正确顺序释放
总结
这种模块化初始化模式非常适合微服务架构的 .NET 项目。通过将初始化逻辑抽象到统一的 AppInitializer 类中,既保证了代码的可维护性,又提供了足够的灵活性来应对不同模块的差异化需求。