.NET 8 模块化初始化架构设计

前言

在开发分布式系统时,我们常常会遇到这样的问题:不同模块(如 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();
    }
}

设计优势

  1. 灵活配置:每个模块可以按需选择初始化哪些组件
  2. 容错机制:非关键组件失败可以选择继续运行
  3. 统一入口:所有初始化逻辑集中管理,便于维护
  4. 优雅关闭:确保资源按正确顺序释放

总结

这种模块化初始化模式非常适合微服务架构的 .NET 项目。通过将初始化逻辑抽象到统一的 AppInitializer 类中,既保证了代码的可维护性,又提供了足够的灵活性来应对不同模块的差异化需求。