mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-08 01:24:31 +08:00
feat(architectures): 添加架构基类和初始化编排功能
- 实现 Architecture 基类,提供系统、模型、工具等组件的注册与管理功能 - 添加 ArchitectureBootstrapper 协调器,负责初始化期间的基础设施准备工作 - 实现生命周期管理、组件注册管理和模块管理功能 - 提供同步和异步初始化方法,支持不同场景下的架构初始化需求 - 添加架构上下文绑定和 IOC 容器冻结功能,确保运行时依赖图稳定 - 实现架构生命周期钩子注册和阶段变更事件功能 - 添加完整的单元测试验证初始化编排流程的正确性
This commit is contained in:
parent
9239e51644
commit
16fae83f70
@ -0,0 +1,188 @@
|
||||
using GFramework.Core.Abstractions.Enums;
|
||||
using GFramework.Core.Abstractions.Events;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Core.Environment;
|
||||
using GFramework.Core.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GFramework.Core.Tests.Architectures;
|
||||
|
||||
/// <summary>
|
||||
/// 验证 <see cref="Architecture" /> 初始化编排流程的单元测试。
|
||||
/// 这些测试覆盖环境初始化、服务准备、上下文绑定和自定义服务配置的时序,
|
||||
/// 以确保核心协调器在拆分后仍保持既有行为。
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ArchitectureInitializationPipelineTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 为每个测试准备独立的日志工厂和游戏上下文状态。
|
||||
/// </summary>
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
|
||||
GameContext.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理测试期间注册的全局游戏上下文,避免跨测试污染。
|
||||
/// </summary>
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
GameContext.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证异步初始化会在执行用户初始化逻辑之前准备环境、服务和上下文。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task InitializeAsync_Should_Prepare_Runtime_Before_OnInitialize()
|
||||
{
|
||||
var environment = new TrackingEnvironment();
|
||||
var marker = new BootstrapMarker();
|
||||
var architecture = new InitializationPipelineTestArchitecture(environment, marker);
|
||||
|
||||
await architecture.InitializeAsync();
|
||||
|
||||
AssertRuntimePrepared(architecture, environment, marker);
|
||||
await architecture.DestroyAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证同步初始化路径复用同一套基础设施准备流程。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task Initialize_Should_Prepare_Runtime_Before_OnInitialize()
|
||||
{
|
||||
var environment = new TrackingEnvironment();
|
||||
var marker = new BootstrapMarker();
|
||||
var architecture = new InitializationPipelineTestArchitecture(environment, marker);
|
||||
|
||||
architecture.Initialize();
|
||||
|
||||
AssertRuntimePrepared(architecture, environment, marker);
|
||||
await architecture.DestroyAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断言初始化阶段所需的运行时准备工作都已经完成。
|
||||
/// </summary>
|
||||
/// <param name="architecture">待验证的测试架构实例。</param>
|
||||
/// <param name="environment">测试使用的环境对象。</param>
|
||||
/// <param name="marker">通过服务配置委托注册的标记服务。</param>
|
||||
private static void AssertRuntimePrepared(
|
||||
InitializationPipelineTestArchitecture architecture,
|
||||
TrackingEnvironment environment,
|
||||
BootstrapMarker marker)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(architecture.ObservedEnvironmentInitialized, Is.True);
|
||||
Assert.That(architecture.ObservedConfiguredServiceAvailable, Is.True);
|
||||
Assert.That(architecture.ObservedEventBusAvailable, Is.True);
|
||||
Assert.That(architecture.ObservedContextWasBound, Is.True);
|
||||
Assert.That(architecture.ObservedEnvironmentRegistered, Is.True);
|
||||
Assert.That(architecture.Context.GetEnvironment(), Is.SameAs(environment));
|
||||
Assert.That(architecture.Context.GetService<BootstrapMarker>(), Is.SameAs(marker));
|
||||
Assert.That(architecture.CurrentPhase, Is.EqualTo(ArchitecturePhase.Ready));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 跟踪初始化期间关键可观察状态的测试架构。
|
||||
/// </summary>
|
||||
private sealed class InitializationPipelineTestArchitecture : Architecture
|
||||
{
|
||||
private readonly TrackingEnvironment _environment;
|
||||
private readonly BootstrapMarker _marker;
|
||||
|
||||
/// <summary>
|
||||
/// 使用可观察环境和标记服务创建测试架构。
|
||||
/// </summary>
|
||||
/// <param name="environment">用于验证初始化时序的环境对象。</param>
|
||||
/// <param name="marker">用于验证服务钩子执行结果的标记服务。</param>
|
||||
public InitializationPipelineTestArchitecture(
|
||||
TrackingEnvironment environment,
|
||||
BootstrapMarker marker)
|
||||
: base(environment: environment)
|
||||
{
|
||||
_environment = environment;
|
||||
_marker = marker;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录用户初始化逻辑执行时环境是否已经准备完成。
|
||||
/// </summary>
|
||||
public bool ObservedEnvironmentInitialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录自定义服务是否已在用户初始化前注册到容器。
|
||||
/// </summary>
|
||||
public bool ObservedConfiguredServiceAvailable { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录内置事件总线是否已在用户初始化前可用。
|
||||
/// </summary>
|
||||
public bool ObservedEventBusAvailable { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录当前上下文是否已在用户初始化前绑定到全局游戏上下文表。
|
||||
/// </summary>
|
||||
public bool ObservedContextWasBound { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录环境对象是否已在用户初始化前注册到架构上下文。
|
||||
/// </summary>
|
||||
public bool ObservedEnvironmentRegistered { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 为容器注册测试标记服务,用于验证初始化前的服务钩子是否执行。
|
||||
/// </summary>
|
||||
public override Action<IServiceCollection>? Configurator => services => services.AddSingleton(_marker);
|
||||
|
||||
/// <summary>
|
||||
/// 在用户初始化逻辑中采集运行时准备状态。
|
||||
/// </summary>
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
ObservedEnvironmentInitialized = _environment.InitializeCallCount == 1;
|
||||
ObservedConfiguredServiceAvailable = ReferenceEquals(Context.GetService<BootstrapMarker>(), _marker);
|
||||
ObservedEventBusAvailable = Context.GetService<IEventBus>() is not null;
|
||||
ObservedContextWasBound = ReferenceEquals(GameContext.GetByType(GetType()), Context);
|
||||
ObservedEnvironmentRegistered = ReferenceEquals(Context.GetEnvironment(), _environment);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于验证环境初始化是否发生的测试环境。
|
||||
/// </summary>
|
||||
private sealed class TrackingEnvironment : EnvironmentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取测试环境名称。
|
||||
/// </summary>
|
||||
public override string Name { get; } = "Tracking";
|
||||
|
||||
/// <summary>
|
||||
/// 获取环境初始化调用次数。
|
||||
/// </summary>
|
||||
public int InitializeCallCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录环境初始化次数。
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
InitializeCallCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过服务配置委托注册到容器的测试标记对象。
|
||||
/// </summary>
|
||||
private sealed class BootstrapMarker
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -37,19 +37,25 @@ public abstract class Architecture : IArchitecture
|
||||
IArchitectureServices? services = null,
|
||||
IArchitectureContext? context = null)
|
||||
{
|
||||
Configuration = configuration ?? new ArchitectureConfiguration();
|
||||
Environment = environment ?? new DefaultEnvironment();
|
||||
Services = services ?? new ArchitectureServices();
|
||||
var resolvedConfiguration = configuration ?? new ArchitectureConfiguration();
|
||||
var resolvedEnvironment = environment ?? new DefaultEnvironment();
|
||||
var resolvedServices = services ?? new ArchitectureServices();
|
||||
_context = context;
|
||||
|
||||
// 初始化 Logger
|
||||
LoggerFactoryResolver.Provider = Configuration.LoggerProperties.LoggerFactoryProvider;
|
||||
LoggerFactoryResolver.Provider = resolvedConfiguration.LoggerProperties.LoggerFactoryProvider;
|
||||
_logger = LoggerFactoryResolver.Provider.CreateLogger(GetType().Name);
|
||||
|
||||
// 初始化管理器
|
||||
_lifecycle = new ArchitectureLifecycle(this, Configuration, Services, _logger);
|
||||
_componentRegistry = new ArchitectureComponentRegistry(this, Configuration, Services, _lifecycle, _logger);
|
||||
_modules = new ArchitectureModules(this, Services, _logger);
|
||||
_bootstrapper = new ArchitectureBootstrapper(GetType(), resolvedEnvironment, resolvedServices, _logger);
|
||||
_lifecycle = new ArchitectureLifecycle(this, resolvedConfiguration, resolvedServices, _logger);
|
||||
_componentRegistry = new ArchitectureComponentRegistry(
|
||||
this,
|
||||
resolvedConfiguration,
|
||||
resolvedServices,
|
||||
_lifecycle,
|
||||
_logger);
|
||||
_modules = new ArchitectureModules(this, resolvedServices, _logger);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -70,21 +76,6 @@ public abstract class Architecture : IArchitecture
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// 获取架构配置对象
|
||||
/// </summary>
|
||||
private IArchitectureConfiguration Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取环境配置对象
|
||||
/// </summary>
|
||||
private IEnvironment Environment { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取服务管理器
|
||||
/// </summary>
|
||||
private IArchitectureServices Services { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前架构的阶段
|
||||
/// </summary>
|
||||
@ -129,6 +120,11 @@ public abstract class Architecture : IArchitecture
|
||||
/// </summary>
|
||||
private IArchitectureContext? _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化基础设施编排器
|
||||
/// </summary>
|
||||
private readonly ArchitectureBootstrapper _bootstrapper;
|
||||
|
||||
/// <summary>
|
||||
/// 生命周期管理器
|
||||
/// </summary>
|
||||
@ -284,32 +280,7 @@ public abstract class Architecture : IArchitecture
|
||||
/// <param name="asyncMode">是否启用异步模式</param>
|
||||
private async Task InitializeInternalAsync(bool asyncMode)
|
||||
{
|
||||
// === 基础环境初始化 ===
|
||||
Environment.Initialize();
|
||||
|
||||
// 注册内置服务模块
|
||||
Services.ModuleManager.RegisterBuiltInModules(Services.Container);
|
||||
|
||||
// 将 Environment 注册到容器
|
||||
if (!Services.Container.Contains<IEnvironment>())
|
||||
Services.Container.RegisterPlurality(Environment);
|
||||
|
||||
// 初始化架构上下文
|
||||
_context ??= new ArchitectureContext(Services.Container);
|
||||
GameContext.Bind(GetType(), _context);
|
||||
|
||||
// 为服务设置上下文
|
||||
Services.SetContext(_context);
|
||||
if (Configurator is null)
|
||||
{
|
||||
_logger.Debug("Mediator-based cqrs will not take effect without the service setter configured!");
|
||||
}
|
||||
|
||||
// 执行服务钩子
|
||||
Services.Container.ExecuteServicesHook(Configurator);
|
||||
|
||||
// 初始化服务模块
|
||||
await Services.ModuleManager.InitializeAllAsync(asyncMode);
|
||||
_context = await _bootstrapper.PrepareForInitializationAsync(_context, Configurator, asyncMode);
|
||||
|
||||
// === 用户 OnInitialize ===
|
||||
_logger.Debug("Calling user OnInitialize()");
|
||||
@ -320,9 +291,7 @@ public abstract class Architecture : IArchitecture
|
||||
await _lifecycle.InitializeAllComponentsAsync(asyncMode);
|
||||
|
||||
// === 初始化完成阶段 ===
|
||||
Services.Container.Freeze();
|
||||
_logger.Info("IOC container frozen");
|
||||
|
||||
_bootstrapper.CompleteInitialization();
|
||||
_lifecycle.MarkAsReady();
|
||||
_logger.Info($"Architecture {GetType().Name} is ready - all components initialized");
|
||||
}
|
||||
|
||||
118
GFramework.Core/Architectures/ArchitectureBootstrapper.cs
Normal file
118
GFramework.Core/Architectures/ArchitectureBootstrapper.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Environment;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GFramework.Core.Architectures;
|
||||
|
||||
/// <summary>
|
||||
/// 协调架构初始化期间的基础设施准备工作。
|
||||
/// 该类型将环境初始化、服务模块启动、上下文绑定和服务容器配置从 <see cref="Architecture" /> 中拆出,
|
||||
/// 使核心架构类只保留生命周期入口和公共 API 协调职责。
|
||||
/// </summary>
|
||||
internal sealed class ArchitectureBootstrapper(
|
||||
Type architectureType,
|
||||
IEnvironment environment,
|
||||
IArchitectureServices services,
|
||||
ILogger logger)
|
||||
{
|
||||
/// <summary>
|
||||
/// 在执行用户 <c>OnInitialize</c> 之前准备架构运行时。
|
||||
/// 该流程必须保证环境、内置服务、上下文和服务钩子已经可用,
|
||||
/// 因为用户初始化逻辑通常会立即访问事件总线、查询执行器或环境对象。
|
||||
/// </summary>
|
||||
/// <param name="existingContext">调用方已经提供的上下文;如果为空则创建默认上下文。</param>
|
||||
/// <param name="configurator">可选的容器配置委托,用于接入 Mediator 等扩展服务。</param>
|
||||
/// <param name="asyncMode">是否以异步模式初始化服务模块。</param>
|
||||
/// <returns>已绑定到当前架构类型的架构上下文。</returns>
|
||||
public async Task<IArchitectureContext> PrepareForInitializationAsync(
|
||||
IArchitectureContext? existingContext,
|
||||
Action<IServiceCollection>? configurator,
|
||||
bool asyncMode)
|
||||
{
|
||||
InitializeEnvironment();
|
||||
RegisterBuiltInModules();
|
||||
EnsureEnvironmentRegistered();
|
||||
|
||||
var context = EnsureContext(existingContext);
|
||||
ConfigureServices(context, configurator);
|
||||
await InitializeServiceModulesAsync(asyncMode);
|
||||
return context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 完成用户组件初始化之后的收尾工作。
|
||||
/// 冻结容器可以阻止 Ready 阶段之后的意外服务注册,保持运行时依赖图稳定。
|
||||
/// </summary>
|
||||
public void CompleteInitialization()
|
||||
{
|
||||
services.Container.Freeze();
|
||||
logger.Info("IOC container frozen");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化运行环境,使环境对象在后续服务构建和用户初始化前进入可用状态。
|
||||
/// </summary>
|
||||
private void InitializeEnvironment()
|
||||
{
|
||||
environment.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册框架内置服务模块。
|
||||
/// 该步骤必须先于执行服务钩子,以便容器具备 CQRS 和事件总线等基础服务。
|
||||
/// </summary>
|
||||
private void RegisterBuiltInModules()
|
||||
{
|
||||
services.ModuleManager.RegisterBuiltInModules(services.Container);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保环境对象可以通过架构容器解析。
|
||||
/// 如果调用方已经预先注册了自定义环境实例,则保留现有绑定,避免覆盖外部配置。
|
||||
/// </summary>
|
||||
private void EnsureEnvironmentRegistered()
|
||||
{
|
||||
if (!services.Container.Contains<IEnvironment>())
|
||||
services.Container.RegisterPlurality(environment);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取本次初始化使用的架构上下文,并将其绑定到全局游戏上下文表。
|
||||
/// 绑定发生在用户初始化之前,确保组件在注册阶段即可通过架构类型解析上下文。
|
||||
/// </summary>
|
||||
/// <param name="existingContext">外部提供的上下文。</param>
|
||||
/// <returns>实际用于本次初始化的上下文实例。</returns>
|
||||
private IArchitectureContext EnsureContext(IArchitectureContext? existingContext)
|
||||
{
|
||||
var context = existingContext ?? new ArchitectureContext(services.Container);
|
||||
GameContext.Bind(architectureType, context);
|
||||
return context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为服务容器设置上下文并执行扩展配置钩子。
|
||||
/// 这一步统一承接 Mediator 等容器扩展的接入点,避免 <see cref="Architecture" /> 直接操作容器细节。
|
||||
/// </summary>
|
||||
/// <param name="context">当前架构上下文。</param>
|
||||
/// <param name="configurator">可选的服务集合配置委托。</param>
|
||||
private void ConfigureServices(IArchitectureContext context, Action<IServiceCollection>? configurator)
|
||||
{
|
||||
services.SetContext(context);
|
||||
|
||||
if (configurator is null)
|
||||
logger.Debug("Mediator-based cqrs will not take effect without the service setter configured!");
|
||||
|
||||
services.Container.ExecuteServicesHook(configurator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化所有服务模块。
|
||||
/// 该过程在用户注册系统、模型和工具之前完成,避免组件在初始化期间访问未准备好的服务。
|
||||
/// </summary>
|
||||
/// <param name="asyncMode">是否允许异步初始化服务模块。</param>
|
||||
private async Task InitializeServiceModulesAsync(bool asyncMode)
|
||||
{
|
||||
await services.ModuleManager.InitializeAllAsync(asyncMode);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user