From 01dc1523a52068948a85ab20405cec740ba24043 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sun, 5 Apr 2026 10:52:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(architecture):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E6=A0=B8=E5=BF=83=E7=BB=84=E4=BB=B6=E5=92=8C?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E6=B3=A8=E5=85=A5=E5=AE=B9=E5=99=A8=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 Architecture 基类,提供系统、模型、工具等组件的注册与管理功能 - 添加 ArchitectureComponentRegistry 组件注册管理器,负责管理系统、模型、工具的注册 - 实现 ArchitectureLifecycle 生命周期管理器,管理架构阶段转换和组件初始化 - 添加 ArchitectureModules 模块管理器,负责架构模块安装和中介行为注册 - 实现 MicrosoftDiContainer 依赖注入容器,包装 Microsoft.Extensions.DependencyInjection - 提供完整的组件生命周期管理,支持同步和异步初始化模式 - 添加架构阶段管理和组件注册验证机制 --- .../Architectures/IArchitecture.cs | 4 +- ...hitectureComponentRegistryBehaviorTests.cs | 306 ++++++++++++++++++ .../ArchitectureLifecycleBehaviorTests.cs | 253 +++++++++++++++ .../ArchitectureModulesBehaviorTests.cs | 188 +++++++++++ GFramework.Core/Architectures/Architecture.cs | 4 +- .../ArchitectureComponentRegistry.cs | 2 + .../Architectures/ArchitectureDisposer.cs | 111 +++++++ .../Architectures/ArchitectureLifecycle.cs | 211 ++---------- .../Architectures/ArchitectureModules.cs | 3 +- .../ArchitecturePhaseCoordinator.cs | 116 +++++++ GFramework.Core/Ioc/MicrosoftDiContainer.cs | 37 ++- 11 files changed, 1046 insertions(+), 189 deletions(-) create mode 100644 GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs create mode 100644 GFramework.Core.Tests/Architectures/ArchitectureLifecycleBehaviorTests.cs create mode 100644 GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs create mode 100644 GFramework.Core/Architectures/ArchitectureDisposer.cs create mode 100644 GFramework.Core/Architectures/ArchitecturePhaseCoordinator.cs diff --git a/GFramework.Core.Abstractions/Architectures/IArchitecture.cs b/GFramework.Core.Abstractions/Architectures/IArchitecture.cs index c2ba8fd6..0055d3fe 100644 --- a/GFramework.Core.Abstractions/Architectures/IArchitecture.cs +++ b/GFramework.Core.Abstractions/Architectures/IArchitecture.cs @@ -74,7 +74,9 @@ public interface IArchitecture : IAsyncInitializable, IAsyncDestroyable, IInitia /// /// 注册中介行为管道 - /// 用于配置Mediator框架的行为拦截和处理逻辑 + /// 用于配置Mediator框架的行为拦截和处理逻辑。 + /// 既支持实现 IPipelineBehavior<,> 的开放泛型行为类型, + /// 也支持绑定到单一请求/响应对的封闭行为类型。 /// /// 行为类型,必须是引用类型 void RegisterMediatorBehavior() diff --git a/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs b/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs new file mode 100644 index 00000000..74344191 --- /dev/null +++ b/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs @@ -0,0 +1,306 @@ +using GFramework.Core.Abstractions.Architectures; +using GFramework.Core.Abstractions.Enums; +using GFramework.Core.Abstractions.Model; +using GFramework.Core.Abstractions.Systems; +using GFramework.Core.Abstractions.Utility; +using GFramework.Core.Architectures; +using GFramework.Core.Logging; + +namespace GFramework.Core.Tests.Architectures; + +/// +/// 验证 Architecture 通过 ArchitectureComponentRegistry 暴露出的组件注册行为。 +/// 这些测试覆盖实例注册、工厂注册、上下文注入、生命周期初始化和 Ready 后注册约束, +/// 用于保护组件注册器在继续重构后的既有契约。 +/// +[TestFixture] +public class ArchitectureComponentRegistryBehaviorTests +{ + /// + /// 初始化日志工厂和全局上下文状态。 + /// + [SetUp] + public void SetUp() + { + LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); + GameContext.Clear(); + } + + /// + /// 清理测试过程中绑定到全局表的架构上下文。 + /// + [TearDown] + public void TearDown() + { + GameContext.Clear(); + } + + /// + /// 验证系统实例注册会注入上下文并参与生命周期初始化。 + /// + [Test] + public async Task RegisterSystem_Instance_Should_Set_Context_And_Initialize_System() + { + var system = new TrackingSystem(); + var architecture = new RegistryTestArchitecture(target => target.RegisterSystem(system)); + + await architecture.InitializeAsync(); + + Assert.Multiple(() => + { + Assert.That(system.GetContext(), Is.SameAs(architecture.Context)); + Assert.That(system.InitializeCallCount, Is.EqualTo(1)); + Assert.That(architecture.Context.GetSystem(), Is.SameAs(system)); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 验证模型实例注册会注入上下文并参与生命周期初始化。 + /// + [Test] + public async Task RegisterModel_Instance_Should_Set_Context_And_Initialize_Model() + { + var model = new TrackingModel(); + var architecture = new RegistryTestArchitecture(target => target.RegisterModel(model)); + + await architecture.InitializeAsync(); + + Assert.Multiple(() => + { + Assert.That(model.GetContext(), Is.SameAs(architecture.Context)); + Assert.That(model.InitializeCallCount, Is.EqualTo(1)); + Assert.That(architecture.Context.GetModel(), Is.SameAs(model)); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 验证上下文工具注册会注入上下文并参与生命周期初始化。 + /// + [Test] + public async Task RegisterUtility_Instance_Should_Set_Context_For_ContextUtility() + { + var utility = new TrackingContextUtility(); + var architecture = new RegistryTestArchitecture(target => target.RegisterUtility(utility)); + + await architecture.InitializeAsync(); + + Assert.Multiple(() => + { + Assert.That(utility.GetContext(), Is.SameAs(architecture.Context)); + Assert.That(utility.InitializeCallCount, Is.EqualTo(1)); + Assert.That(architecture.Context.GetUtility(), Is.SameAs(utility)); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 验证普通工具的工厂注册会在首次解析时创建单例并执行创建回调。 + /// + [Test] + public async Task RegisterUtility_Type_Should_Create_Singleton_And_Invoke_Callback() + { + FactoryCreatedUtility? callbackInstance = null; + var architecture = new RegistryTestArchitecture(target => + target.RegisterUtility(created => callbackInstance = created)); + + await architecture.InitializeAsync(); + + var first = architecture.Context.GetUtility(); + var second = architecture.Context.GetUtility(); + + Assert.Multiple(() => + { + Assert.That(callbackInstance, Is.SameAs(first)); + Assert.That(second, Is.SameAs(first)); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 验证 Ready 阶段后不允许继续注册 Utility,保持与系统和模型一致的约束。 + /// + [Test] + public async Task RegisterUtility_After_Ready_Should_Throw_InvalidOperationException() + { + var architecture = new RegistryTestArchitecture(_ => { }); + await architecture.InitializeAsync(); + + Assert.That( + () => architecture.RegisterUtility(new TrackingContextUtility()), + Throws.InvalidOperationException.With.Message.EqualTo( + "Cannot register utility after Architecture is Ready")); + + await architecture.DestroyAsync(); + } + + /// + /// 用于测试组件注册行为的最小架构实现。 + /// + private sealed class RegistryTestArchitecture(Action registrationAction) : Architecture + { + /// + /// 在初始化阶段执行测试注入的注册逻辑。 + /// + protected override void OnInitialize() + { + registrationAction(this); + } + } + + /// + /// 记录初始化与上下文注入情况的测试系统。 + /// + private sealed class TrackingSystem : ISystem + { + private IArchitectureContext _context = null!; + + /// + /// 获取系统初始化调用次数。 + /// + public int InitializeCallCount { get; private set; } + + /// + /// 记录初始化调用。 + /// + public void Initialize() + { + InitializeCallCount++; + } + + /// + /// 该测试系统不关心阶段变更。 + /// + /// 当前架构阶段。 + public void OnArchitecturePhase(ArchitecturePhase phase) + { + } + + /// + /// 存储注入的架构上下文。 + /// + /// 架构上下文。 + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + /// + /// 返回当前持有的架构上下文。 + /// + public IArchitectureContext GetContext() + { + return _context; + } + + /// + /// 该测试系统没有额外销毁逻辑。 + /// + public void Destroy() + { + } + } + + /// + /// 记录初始化与上下文注入情况的测试模型。 + /// + private sealed class TrackingModel : IModel + { + private IArchitectureContext _context = null!; + + /// + /// 获取模型初始化调用次数。 + /// + public int InitializeCallCount { get; private set; } + + /// + /// 记录初始化调用。 + /// + public void Initialize() + { + InitializeCallCount++; + } + + /// + /// 该测试模型不关心阶段变更。 + /// + /// 当前架构阶段。 + public void OnArchitecturePhase(ArchitecturePhase phase) + { + } + + /// + /// 存储注入的架构上下文。 + /// + /// 架构上下文。 + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + /// + /// 返回当前持有的架构上下文。 + /// + public IArchitectureContext GetContext() + { + return _context; + } + } + + /// + /// 记录初始化与上下文注入情况的测试上下文工具。 + /// + private sealed class TrackingContextUtility : IContextUtility + { + private IArchitectureContext _context = null!; + + /// + /// 获取工具初始化调用次数。 + /// + public int InitializeCallCount { get; private set; } + + /// + /// 记录初始化调用。 + /// + public void Initialize() + { + InitializeCallCount++; + } + + /// + /// 存储注入的架构上下文。 + /// + /// 架构上下文。 + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + /// + /// 返回当前持有的架构上下文。 + /// + public IArchitectureContext GetContext() + { + return _context; + } + + /// + /// 该测试工具没有额外销毁逻辑。 + /// + public void Destroy() + { + } + } + + /// + /// 用于验证普通工厂注册路径的简单工具。 + /// + private sealed class FactoryCreatedUtility : IUtility + { + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/Architectures/ArchitectureLifecycleBehaviorTests.cs b/GFramework.Core.Tests/Architectures/ArchitectureLifecycleBehaviorTests.cs new file mode 100644 index 00000000..0bde4b5d --- /dev/null +++ b/GFramework.Core.Tests/Architectures/ArchitectureLifecycleBehaviorTests.cs @@ -0,0 +1,253 @@ +using GFramework.Core.Abstractions.Architectures; +using GFramework.Core.Abstractions.Enums; +using GFramework.Core.Abstractions.Lifecycle; +using GFramework.Core.Abstractions.Model; +using GFramework.Core.Abstractions.Systems; +using GFramework.Core.Abstractions.Utility; +using GFramework.Core.Architectures; +using GFramework.Core.Logging; + +namespace GFramework.Core.Tests.Architectures; + +/// +/// 验证 Architecture 生命周期行为的集成测试。 +/// 这些测试覆盖阶段流转、失败状态传播和逆序销毁规则, +/// 用于保护拆分后的生命周期管理、阶段协调与销毁协调行为。 +/// +[TestFixture] +public class ArchitectureLifecycleBehaviorTests +{ + /// + /// 为每个测试准备独立的日志工厂和全局上下文状态。 + /// + [SetUp] + public void SetUp() + { + LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); + GameContext.Clear(); + } + + /// + /// 清理测试注册到全局上下文表的架构上下文。 + /// + [TearDown] + public void TearDown() + { + GameContext.Clear(); + } + + /// + /// 验证初始化流程会按既定顺序推进所有生命周期阶段。 + /// + [Test] + public async Task InitializeAsync_Should_Enter_Expected_Phases_In_Order() + { + var architecture = new PhaseTrackingArchitecture(); + + await architecture.InitializeAsync(); + + Assert.That(architecture.PhaseHistory, Is.EqualTo(new[] + { + ArchitecturePhase.BeforeUtilityInit, + ArchitecturePhase.AfterUtilityInit, + ArchitecturePhase.BeforeModelInit, + ArchitecturePhase.AfterModelInit, + ArchitecturePhase.BeforeSystemInit, + ArchitecturePhase.AfterSystemInit, + ArchitecturePhase.Ready + })); + + await architecture.DestroyAsync(); + } + + /// + /// 验证用户初始化失败时,等待 Ready 的任务会失败并进入 FailedInitialization 阶段。 + /// + [Test] + public async Task InitializeAsync_When_OnInitialize_Throws_Should_Mark_FailedInitialization() + { + var architecture = new PhaseTrackingArchitecture(() => throw new InvalidOperationException("boom")); + + var exception = Assert.ThrowsAsync(async () => await architecture.InitializeAsync()); + Assert.That(exception, Is.Not.Null); + Assert.That(architecture.CurrentPhase, Is.EqualTo(ArchitecturePhase.FailedInitialization)); + Assert.ThrowsAsync(async () => await architecture.WaitUntilReadyAsync()); + } + + /// + /// 验证销毁流程会按注册逆序释放组件,并推进 Destroying/Destroyed 阶段。 + /// + [Test] + public async Task DestroyAsync_Should_Destroy_Components_In_Reverse_Registration_Order() + { + var destroyOrder = new List(); + var architecture = new DestroyOrderArchitecture(destroyOrder); + + await architecture.InitializeAsync(); + await architecture.DestroyAsync(); + + Assert.Multiple(() => + { + Assert.That(destroyOrder, Is.EqualTo(new[] { "system", "model", "utility" })); + Assert.That(architecture.CurrentPhase, Is.EqualTo(ArchitecturePhase.Destroyed)); + Assert.That(architecture.PhaseHistory[^2..], Is.EqualTo(new[] + { + ArchitecturePhase.Destroying, + ArchitecturePhase.Destroyed + })); + }); + } + + /// + /// 记录阶段流转的可配置测试架构。 + /// + private sealed class PhaseTrackingArchitecture : Architecture + { + private readonly Action? _onInitializeAction; + + /// + /// 创建一个可选地在用户初始化阶段执行自定义逻辑的测试架构。 + /// + /// 用户初始化时执行的测试回调。 + public PhaseTrackingArchitecture(Action? onInitializeAction = null) + { + _onInitializeAction = onInitializeAction; + PhaseChanged += phase => PhaseHistory.Add(phase); + } + + /// + /// 获取架构经历过的阶段列表。 + /// + public List PhaseHistory { get; } = []; + + /// + /// 执行测试注入的初始化逻辑。 + /// + protected override void OnInitialize() + { + _onInitializeAction?.Invoke(); + } + } + + /// + /// 在初始化时注册可销毁组件的测试架构。 + /// + private sealed class DestroyOrderArchitecture : Architecture + { + private readonly List _destroyOrder; + + /// + /// 创建用于验证销毁顺序的测试架构。 + /// + /// 记录组件销毁顺序的列表。 + public DestroyOrderArchitecture(List destroyOrder) + { + _destroyOrder = destroyOrder; + PhaseChanged += phase => PhaseHistory.Add(phase); + } + + /// + /// 获取架构经历过的阶段列表。 + /// + public List PhaseHistory { get; } = []; + + /// + /// 注册会记录销毁顺序的 Utility、Model 和 System。 + /// + protected override void OnInitialize() + { + RegisterUtility(new TrackingDestroyableUtility(_destroyOrder)); + RegisterModel(new TrackingDestroyableModel(_destroyOrder)); + RegisterSystem(new TrackingDestroyableSystem(_destroyOrder)); + } + } + + /// + /// 用于验证逆序销毁的上下文工具。 + /// + private sealed class TrackingDestroyableUtility(List destroyOrder) : IContextUtility + { + private IArchitectureContext _context = null!; + + public void Initialize() + { + } + + public void Destroy() + { + destroyOrder.Add("utility"); + } + + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + public IArchitectureContext GetContext() + { + return _context; + } + } + + /// + /// 用于验证逆序销毁的模型。 + /// + private sealed class TrackingDestroyableModel(List destroyOrder) : IModel, IDestroyable + { + private IArchitectureContext _context = null!; + + public void Destroy() + { + destroyOrder.Add("model"); + } + + public void Initialize() + { + } + + public void OnArchitecturePhase(ArchitecturePhase phase) + { + } + + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + public IArchitectureContext GetContext() + { + return _context; + } + } + + /// + /// 用于验证逆序销毁的系统。 + /// + private sealed class TrackingDestroyableSystem(List destroyOrder) : ISystem + { + private IArchitectureContext _context = null!; + + public void Initialize() + { + } + + public void Destroy() + { + destroyOrder.Add("system"); + } + + public void OnArchitecturePhase(ArchitecturePhase phase) + { + } + + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + public IArchitectureContext GetContext() + { + return _context; + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs b/GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs new file mode 100644 index 00000000..05601230 --- /dev/null +++ b/GFramework.Core.Tests/Architectures/ArchitectureModulesBehaviorTests.cs @@ -0,0 +1,188 @@ +using GFramework.Core.Abstractions.Architectures; +using GFramework.Core.Abstractions.Utility; +using GFramework.Core.Architectures; +using GFramework.Core.Logging; +using Mediator; +using Microsoft.Extensions.DependencyInjection; + +namespace GFramework.Core.Tests.Architectures; + +/// +/// 验证 Architecture 通过 ArchitectureModules 暴露出的模块安装与 Mediator 行为注册能力。 +/// 这些测试覆盖模块安装回调和中介管道行为接入,确保模块管理器仍然保持可观察行为不变。 +/// +[TestFixture] +public class ArchitectureModulesBehaviorTests +{ + /// + /// 初始化日志工厂和全局上下文状态。 + /// + [SetUp] + public void SetUp() + { + LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); + GameContext.Clear(); + TrackingPipelineBehavior.InvocationCount = 0; + } + + /// + /// 清理测试过程中写入的全局上下文状态。 + /// + [TearDown] + public void TearDown() + { + GameContext.Clear(); + TrackingPipelineBehavior.InvocationCount = 0; + } + + /// + /// 验证安装模块时会把当前架构实例传给模块,并允许模块在安装阶段注册组件。 + /// + [Test] + public async Task InstallModule_Should_Invoke_Module_Install_With_Current_Architecture() + { + var module = new TrackingArchitectureModule(); + var architecture = new ModuleTestArchitecture(target => target.InstallModule(module)); + + await architecture.InitializeAsync(); + + Assert.Multiple(() => + { + Assert.That(module.InstalledArchitecture, Is.SameAs(architecture)); + Assert.That(module.InstallCallCount, Is.EqualTo(1)); + Assert.That(architecture.Context.GetUtility(), Is.Not.Null); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 验证注册的 Mediator 行为会参与请求管道执行。 + /// + [Test] + public async Task RegisterMediatorBehavior_Should_Apply_Pipeline_Behavior_To_Request() + { + var architecture = new ModuleTestArchitecture(target => + target.RegisterMediatorBehavior>()); + + await architecture.InitializeAsync(); + + var response = await architecture.Context.SendRequestAsync(new ModuleBehaviorRequest()); + + Assert.Multiple(() => + { + Assert.That(response, Is.EqualTo("handled")); + Assert.That(TrackingPipelineBehavior.InvocationCount, Is.EqualTo(1)); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 用于测试模块行为的最小架构实现。 + /// + private sealed class ModuleTestArchitecture(Action registrationAction) : Architecture + { + /// + /// 打开 Mediator 服务注册,以便测试中介行为接入。 + /// + public override Action? Configurator => + services => services.AddMediator(options => { options.ServiceLifetime = ServiceLifetime.Singleton; }); + + /// + /// 在初始化阶段执行测试注入的模块注册逻辑。 + /// + protected override void OnInitialize() + { + registrationAction(this); + } + } + + /// + /// 记录模块安装调用情况的测试模块。 + /// + private sealed class TrackingArchitectureModule : IArchitectureModule + { + /// + /// 获取模块安装调用次数。 + /// + public int InstallCallCount { get; private set; } + + /// + /// 获取最近一次接收到的架构实例。 + /// + public IArchitecture? InstalledArchitecture { get; private set; } + + /// + /// 记录安装调用,并在安装阶段注册一个工具验证调用链可用。 + /// + /// 目标架构实例。 + public void Install(IArchitecture architecture) + { + InstallCallCount++; + InstalledArchitecture = architecture; + architecture.RegisterUtility(new InstalledByModuleUtility()); + } + } + + /// + /// 由测试模块安装时注册的简单工具。 + /// + private sealed class InstalledByModuleUtility : IUtility + { + } +} + +/// +/// 用于验证管道行为注册是否生效的测试请求。 +/// +public sealed class ModuleBehaviorRequest : IRequest +{ +} + +/// +/// 处理测试请求的处理器。 +/// +public sealed class ModuleBehaviorRequestHandler : IRequestHandler +{ + /// + /// 返回固定结果,便于聚焦验证管道行为是否执行。 + /// + /// 请求实例。 + /// 取消令牌。 + /// 固定响应内容。 + public ValueTask Handle(ModuleBehaviorRequest request, CancellationToken cancellationToken) + { + return ValueTask.FromResult("handled"); + } +} + +/// +/// 记录请求通过管道次数的测试行为。 +/// +/// 请求类型。 +/// 响应类型。 +public sealed class TrackingPipelineBehavior : IPipelineBehavior + where TRequest : IRequest +{ + /// + /// 获取当前测试进程中该请求类型对应的行为触发次数。 + /// + public static int InvocationCount { get; set; } + + /// + /// 记录一次行为执行,然后继续执行下一个处理器。 + /// + /// 当前请求消息。 + /// 下一个处理委托。 + /// 取消令牌。 + /// 下游处理器的响应结果。 + public async ValueTask Handle( + TRequest message, + MessageHandlerDelegate next, + CancellationToken cancellationToken) + { + InvocationCount++; + return await next(message, cancellationToken); + } +} \ No newline at end of file diff --git a/GFramework.Core/Architectures/Architecture.cs b/GFramework.Core/Architectures/Architecture.cs index cabffb0e..af96d03f 100644 --- a/GFramework.Core/Architectures/Architecture.cs +++ b/GFramework.Core/Architectures/Architecture.cs @@ -16,6 +16,7 @@ namespace GFramework.Core.Architectures; /// 专注于生命周期管理、初始化流程控制和架构阶段转换。 /// /// 重构说明:此类已重构为协调器模式,将职责委托给专门的管理器: +/// - ArchitectureBootstrapper: 初始化基础设施编排 /// - ArchitectureLifecycle: 生命周期管理 /// - ArchitectureComponentRegistry: 组件注册管理 /// - ArchitectureModules: 模块管理 @@ -146,7 +147,8 @@ public abstract class Architecture : IArchitecture /// /// 注册中介行为管道 - /// 用于配置Mediator框架的行为拦截和处理逻辑 + /// 用于配置Mediator框架的行为拦截和处理逻辑。 + /// 可以传入开放泛型行为类型,也可以传入绑定到特定请求的封闭行为类型。 /// /// 行为类型,必须是引用类型 public void RegisterMediatorBehavior() where TBehavior : class diff --git a/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs b/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs index d39d5972..91b2a846 100644 --- a/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs +++ b/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs @@ -155,6 +155,7 @@ internal sealed class ArchitectureComponentRegistry( /// 注册成功的工具实例 public TUtility RegisterUtility(TUtility utility) where TUtility : IUtility { + ValidateRegistration("utility"); logger.Debug($"Registering utility: {typeof(TUtility).Name}"); // 处理上下文工具类型的设置和生命周期管理 @@ -177,6 +178,7 @@ internal sealed class ArchitectureComponentRegistry( /// 可选的实例创建后回调 public void RegisterUtility(Action? onCreated = null) where T : class, IUtility { + ValidateRegistration("utility"); logger.Debug($"Registering utility type: {typeof(T).Name}"); services.Container.RegisterFactory(sp => diff --git a/GFramework.Core/Architectures/ArchitectureDisposer.cs b/GFramework.Core/Architectures/ArchitectureDisposer.cs new file mode 100644 index 00000000..1c1a861d --- /dev/null +++ b/GFramework.Core/Architectures/ArchitectureDisposer.cs @@ -0,0 +1,111 @@ +using GFramework.Core.Abstractions.Architectures; +using GFramework.Core.Abstractions.Enums; +using GFramework.Core.Abstractions.Lifecycle; +using GFramework.Core.Abstractions.Logging; + +namespace GFramework.Core.Architectures; + +/// +/// 统一处理架构内可销毁对象的登记与释放。 +/// 该类型封装逆序销毁、异常隔离和服务模块清理规则, +/// 让 可以专注于初始化流程本身。 +/// +internal sealed class ArchitectureDisposer( + IArchitectureServices services, + ILogger logger) +{ + /// + /// 保留注册顺序的可销毁对象列表。 + /// 销毁时按逆序遍历,以尽量匹配组件间的依赖方向。 + /// + private readonly List _disposables = []; + + /// + /// 用于去重的可销毁对象集合。 + /// + private readonly HashSet _disposableSet = []; + + /// + /// 注册一个需要参与架构销毁流程的对象。 + /// 只有实现 的对象会被跟踪。 + /// + /// 待检查的组件实例。 + public void Register(object component) + { + if (component is not (IDestroyable or IAsyncDestroyable)) + return; + + if (!_disposableSet.Add(component)) + return; + + _disposables.Add(component); + logger.Trace($"Registered {component.GetType().Name} for destruction"); + } + + /// + /// 执行架构销毁流程。 + /// 该方法会根据当前阶段决定是否进入 Destroying/Destroyed 阶段,并负责服务模块与容器清理。 + /// + /// 销毁开始前的架构阶段。 + /// 用于推进架构阶段的回调。 + public async ValueTask DestroyAsync(ArchitecturePhase currentPhase, Action enterPhase) + { + if (currentPhase >= ArchitecturePhase.Destroying) + { + logger.Warn("Architecture destroy called but already in destroying/destroyed state"); + return; + } + + if (currentPhase == ArchitecturePhase.None) + { + logger.Debug("Architecture destroy called but never initialized, cleaning up registered components"); + await CleanupComponentsAsync(); + return; + } + + logger.Info("Starting architecture destruction"); + enterPhase(ArchitecturePhase.Destroying); + + await CleanupComponentsAsync(); + await services.ModuleManager.DestroyAllAsync(); + services.Container.Clear(); + + enterPhase(ArchitecturePhase.Destroyed); + logger.Info("Architecture destruction completed"); + } + + /// + /// 逆序销毁当前已注册的所有可销毁组件。 + /// 单个组件失败不会中断后续清理,避免在销毁阶段留下半清理状态。 + /// + private async ValueTask CleanupComponentsAsync() + { + logger.Info($"Destroying {_disposables.Count} disposable components"); + + for (var i = _disposables.Count - 1; i >= 0; i--) + { + var component = _disposables[i]; + + try + { + logger.Debug($"Destroying component: {component.GetType().Name}"); + + if (component is IAsyncDestroyable asyncDestroyable) + { + await asyncDestroyable.DestroyAsync(); + } + else if (component is IDestroyable destroyable) + { + destroyable.Destroy(); + } + } + catch (Exception ex) + { + logger.Error($"Error destroying {component.GetType().Name}", ex); + } + } + + _disposables.Clear(); + _disposableSet.Clear(); + } +} \ No newline at end of file diff --git a/GFramework.Core/Architectures/ArchitectureLifecycle.cs b/GFramework.Core/Architectures/ArchitectureLifecycle.cs index dbe26291..85c06ed7 100644 --- a/GFramework.Core/Architectures/ArchitectureLifecycle.cs +++ b/GFramework.Core/Architectures/ArchitectureLifecycle.cs @@ -27,11 +27,7 @@ internal sealed class ArchitectureLifecycle( /// 注册的钩子实例 public IArchitectureLifecycleHook RegisterLifecycleHook(IArchitectureLifecycleHook hook) { - if (CurrentPhase >= ArchitecturePhase.Ready && !configuration.ArchitectureProperties.AllowLateRegistration) - throw new InvalidOperationException( - "Cannot register lifecycle hook after architecture is Ready"); - _lifecycleHooks.Add(hook); - return hook; + return _phaseCoordinator.RegisterLifecycleHook(hook); } #endregion @@ -44,31 +40,32 @@ internal sealed class ArchitectureLifecycle( /// 要注册的组件 public void RegisterLifecycleComponent(object component) { - // 处理初始化 if (component is IInitializable initializable) { - if (!_initialized) + if (_initialized) + throw new InvalidOperationException("Cannot initialize component after Architecture is Ready"); + + if (_pendingInitializableSet.Add(initializable)) { - // 原子去重:HashSet.Add 返回 true 表示添加成功(之前不存在) - if (_pendingInitializableSet.Add(initializable)) - { - _pendingInitializableList.Add(initializable); - logger.Trace($"Added {component.GetType().Name} to pending initialization queue"); - } - } - else - { - throw new InvalidOperationException( - "Cannot initialize component after Architecture is Ready"); + _pendingInitializableList.Add(initializable); + logger.Trace($"Added {component.GetType().Name} to pending initialization queue"); } } - // 处理销毁(支持 IDestroyable 或 IAsyncDestroyable) - if (component is not (IDestroyable or IAsyncDestroyable)) return; - // 原子去重:HashSet.Add 返回 true 表示添加成功(之前不存在) - if (!_disposableSet.Add(component)) return; - _disposables.Add(component); - logger.Trace($"Registered {component.GetType().Name} for destruction"); + _disposer.Register(component); + } + + #endregion + + #region Phase Management + + /// + /// 进入指定的架构阶段,并执行相应的生命周期管理操作 + /// + /// 要进入的下一个架构阶段 + public void EnterPhase(ArchitecturePhase next) + { + _phaseCoordinator.EnterPhase(next); } #endregion @@ -88,19 +85,15 @@ internal sealed class ArchitectureLifecycle( private readonly List _pendingInitializableList = []; /// - /// 可销毁组件的去重集合(支持 IDestroyable 和 IAsyncDestroyable) + /// 架构阶段协调器 /// - private readonly HashSet _disposableSet = []; + private readonly ArchitecturePhaseCoordinator _phaseCoordinator = + new(architecture, configuration, services, logger); /// - /// 存储所有需要销毁的组件(统一管理,保持注册逆序销毁) + /// 架构销毁协调器 /// - private readonly List _disposables = []; - - /// - /// 生命周期感知对象列表 - /// - private readonly List _lifecycleHooks = []; + private readonly ArchitectureDisposer _disposer = new(services, logger); /// /// 标记架构是否已初始化完成 @@ -114,7 +107,7 @@ internal sealed class ArchitectureLifecycle( /// /// 当前架构的阶段 /// - public ArchitecturePhase CurrentPhase { get; private set; } + public ArchitecturePhase CurrentPhase => _phaseCoordinator.CurrentPhase; /// /// 获取一个布尔值,指示当前架构是否处于就绪状态 @@ -129,87 +122,10 @@ internal sealed class ArchitectureLifecycle( /// /// 阶段变更事件(用于测试和扩展) /// - public event Action? PhaseChanged; - - #endregion - - #region Phase Management - - /// - /// 进入指定的架构阶段,并执行相应的生命周期管理操作 - /// - /// 要进入的下一个架构阶段 - /// 当阶段转换不被允许时抛出异常 - public void EnterPhase(ArchitecturePhase next) + public event Action? PhaseChanged { - // 验证阶段转换 - ValidatePhaseTransition(next); - - // 执行阶段转换 - var previousPhase = CurrentPhase; - CurrentPhase = next; - - if (previousPhase != next) - logger.Info($"Architecture phase changed: {previousPhase} -> {next}"); - - // 通知阶段变更 - NotifyPhase(next); - NotifyPhaseAwareObjects(next); - - // 触发阶段变更事件(用于测试和扩展) - PhaseChanged?.Invoke(next); - } - - /// - /// 验证阶段转换是否合法 - /// - /// 目标阶段 - /// 当阶段转换不合法时抛出 - private void ValidatePhaseTransition(ArchitecturePhase next) - { - // 不需要严格验证,直接返回 - if (!configuration.ArchitectureProperties.StrictPhaseValidation) - return; - - // FailedInitialization 可以从任何阶段转换,直接返回 - if (next == ArchitecturePhase.FailedInitialization) - return; - - // 检查转换是否在允许列表中 - if (ArchitectureConstants.PhaseTransitions.TryGetValue(CurrentPhase, out var allowed) && - allowed.Contains(next)) - return; - - // 转换不合法,抛出异常 - var errorMsg = $"Invalid phase transition: {CurrentPhase} -> {next}"; - logger.Fatal(errorMsg); - throw new InvalidOperationException(errorMsg); - } - - /// - /// 通知所有架构阶段感知对象阶段变更 - /// - /// 新阶段 - private void NotifyPhaseAwareObjects(ArchitecturePhase phase) - { - foreach (var obj in services.Container.GetAll()) - { - logger.Trace($"Notifying phase-aware object {obj.GetType().Name} of phase change to {phase}"); - obj.OnArchitecturePhase(phase); - } - } - - /// - /// 通知所有生命周期钩子当前阶段变更 - /// - /// 当前架构阶段 - private void NotifyPhase(ArchitecturePhase phase) - { - foreach (var hook in _lifecycleHooks) - { - hook.OnPhase(phase, architecture); - logger.Trace($"Notifying lifecycle hook {hook.GetType().Name} of phase {phase}"); - } + add => _phaseCoordinator.PhaseChanged += value; + remove => _phaseCoordinator.PhaseChanged -= value; } #endregion @@ -311,72 +227,7 @@ internal sealed class ArchitectureLifecycle( /// public async ValueTask DestroyAsync() { - // 检查当前阶段,如果已经处于销毁或已销毁状态则直接返回 - if (CurrentPhase >= ArchitecturePhase.Destroying) - { - logger.Warn("Architecture destroy called but already in destroying/destroyed state"); - return; - } - - // 如果从未初始化(None 阶段),只清理已注册的组件,不进行阶段转换 - if (CurrentPhase == ArchitecturePhase.None) - { - logger.Debug("Architecture destroy called but never initialized, cleaning up registered components"); - await CleanupComponentsAsync(); - return; - } - - // 进入销毁阶段 - logger.Info("Starting architecture destruction"); - EnterPhase(ArchitecturePhase.Destroying); - - // 清理所有组件 - await CleanupComponentsAsync(); - - // 销毁服务模块 - await services.ModuleManager.DestroyAllAsync(); - - services.Container.Clear(); - - // 进入已销毁阶段 - EnterPhase(ArchitecturePhase.Destroyed); - logger.Info("Architecture destruction completed"); - } - - /// - /// 清理所有已注册的可销毁组件 - /// - private async ValueTask CleanupComponentsAsync() - { - // 销毁所有实现了 IAsyncDestroyable 或 IDestroyable 的组件(按注册逆序销毁) - logger.Info($"Destroying {_disposables.Count} disposable components"); - - for (var i = _disposables.Count - 1; i >= 0; i--) - { - var component = _disposables[i]; - try - { - logger.Debug($"Destroying component: {component.GetType().Name}"); - - // 优先使用异步销毁 - if (component is IAsyncDestroyable asyncDestroyable) - { - await asyncDestroyable.DestroyAsync(); - } - else if (component is IDestroyable destroyable) - { - destroyable.Destroy(); - } - } - catch (Exception ex) - { - logger.Error($"Error destroying {component.GetType().Name}", ex); - // 继续销毁其他组件,不会因为一个组件失败而中断 - } - } - - _disposables.Clear(); - _disposableSet.Clear(); + await _disposer.DestroyAsync(CurrentPhase, EnterPhase); } /// diff --git a/GFramework.Core/Architectures/ArchitectureModules.cs b/GFramework.Core/Architectures/ArchitectureModules.cs index 3b60cc25..94acae78 100644 --- a/GFramework.Core/Architectures/ArchitectureModules.cs +++ b/GFramework.Core/Architectures/ArchitectureModules.cs @@ -14,7 +14,8 @@ internal sealed class ArchitectureModules( { /// /// 注册中介行为管道 - /// 用于配置Mediator框架的行为拦截和处理逻辑 + /// 用于配置Mediator框架的行为拦截和处理逻辑。 + /// 支持开放泛型行为类型和针对单一请求的封闭行为类型。 /// /// 行为类型,必须是引用类型 public void RegisterMediatorBehavior() where TBehavior : class diff --git a/GFramework.Core/Architectures/ArchitecturePhaseCoordinator.cs b/GFramework.Core/Architectures/ArchitecturePhaseCoordinator.cs new file mode 100644 index 00000000..e1fc5f9d --- /dev/null +++ b/GFramework.Core/Architectures/ArchitecturePhaseCoordinator.cs @@ -0,0 +1,116 @@ +using GFramework.Core.Abstractions.Architectures; +using GFramework.Core.Abstractions.Enums; +using GFramework.Core.Abstractions.Logging; + +namespace GFramework.Core.Architectures; + +/// +/// 负责架构阶段流转的验证与通知。 +/// 该类型集中管理阶段值、生命周期钩子和阶段监听器,避免 +/// 同时承担阶段广播与组件初始化队列管理两类职责。 +/// +internal sealed class ArchitecturePhaseCoordinator( + IArchitecture architecture, + IArchitectureConfiguration configuration, + IArchitectureServices services, + ILogger logger) +{ + private readonly List _lifecycleHooks = []; + + /// + /// 获取当前架构阶段。 + /// + public ArchitecturePhase CurrentPhase { get; private set; } + + /// + /// 在架构阶段变更时触发。 + /// 该事件用于测试和扩展场景,保持现有公共行为不变。 + /// + public event Action? PhaseChanged; + + /// + /// 注册一个生命周期钩子。 + /// 就绪后是否允许追加注册由架构配置控制,以保证阶段回调的一致性。 + /// + /// 要注册的生命周期钩子。 + /// 原样返回注册的钩子实例,便于链式调用或测试断言。 + public IArchitectureLifecycleHook RegisterLifecycleHook(IArchitectureLifecycleHook hook) + { + if (CurrentPhase >= ArchitecturePhase.Ready && !configuration.ArchitectureProperties.AllowLateRegistration) + throw new InvalidOperationException("Cannot register lifecycle hook after architecture is Ready"); + + _lifecycleHooks.Add(hook); + return hook; + } + + /// + /// 进入指定阶段并广播给所有阶段消费者。 + /// 顺序保持为“更新阶段值 → 生命周期钩子 → 容器中的阶段监听器 → 外部事件”, + /// 以兼容既有调用约定。 + /// + /// 目标阶段。 + public void EnterPhase(ArchitecturePhase next) + { + ValidatePhaseTransition(next); + + var previousPhase = CurrentPhase; + CurrentPhase = next; + + if (previousPhase != next) + logger.Info($"Architecture phase changed: {previousPhase} -> {next}"); + + NotifyLifecycleHooks(next); + NotifyPhaseListeners(next); + PhaseChanged?.Invoke(next); + } + + /// + /// 根据配置验证阶段迁移是否合法。 + /// 在关闭严格校验时直接放行,以兼容对阶段流转有特殊需求的宿主。 + /// + /// 目标阶段。 + /// 当迁移不在允许集合中时抛出。 + private void ValidatePhaseTransition(ArchitecturePhase next) + { + if (!configuration.ArchitectureProperties.StrictPhaseValidation) + return; + + if (next == ArchitecturePhase.FailedInitialization) + return; + + if (ArchitectureConstants.PhaseTransitions.TryGetValue(CurrentPhase, out var allowed) && allowed.Contains(next)) + return; + + var errorMessage = $"Invalid phase transition: {CurrentPhase} -> {next}"; + logger.Fatal(errorMessage); + throw new InvalidOperationException(errorMessage); + } + + /// + /// 通知所有生命周期钩子当前阶段已变更。 + /// 生命周期钩子通常承载注册表装配等框架扩展逻辑,因此优先于普通阶段监听器执行。 + /// + /// 当前阶段。 + private void NotifyLifecycleHooks(ArchitecturePhase phase) + { + foreach (var hook in _lifecycleHooks) + { + hook.OnPhase(phase, architecture); + logger.Trace($"Notifying lifecycle hook {hook.GetType().Name} of phase {phase}"); + } + } + + /// + /// 通知容器中的阶段监听器当前阶段已变更。 + /// 这些对象通常是系统、模型或工具本身,依赖容器解析保证通知范围与运行时实例一致。 + /// + /// 当前阶段。 + private void NotifyPhaseListeners(ArchitecturePhase phase) + { + foreach (var listener in services.Container.GetAll()) + { + logger.Trace($"Notifying phase-aware object {listener.GetType().Name} of phase change to {phase}"); + listener.OnArchitecturePhase(phase); + } + } +} \ No newline at end of file diff --git a/GFramework.Core/Ioc/MicrosoftDiContainer.cs b/GFramework.Core/Ioc/MicrosoftDiContainer.cs index 48373fbf..2615ca52 100644 --- a/GFramework.Core/Ioc/MicrosoftDiContainer.cs +++ b/GFramework.Core/Ioc/MicrosoftDiContainer.cs @@ -311,7 +311,9 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// /// 注册中介行为管道 - /// 用于配置Mediator框架的行为拦截和处理逻辑 + /// 用于配置Mediator框架的行为拦截和处理逻辑。 + /// 同时支持开放泛型行为类型和已闭合的具体行为类型, + /// 以兼容通用行为和针对单一请求的专用行为两种注册方式。 /// /// 行为类型,必须是引用类型 public void RegisterMediatorBehavior() where TBehavior : class @@ -321,12 +323,35 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) { ThrowIfFrozen(); - GetServicesUnsafe.AddSingleton( - typeof(IPipelineBehavior<,>), - typeof(TBehavior) - ); + var behaviorType = typeof(TBehavior); - _logger.Debug($"Mediator behavior registered: {typeof(TBehavior).Name}"); + if (behaviorType.IsGenericTypeDefinition) + { + GetServicesUnsafe.AddSingleton(typeof(IPipelineBehavior<,>), behaviorType); + } + else + { + var pipelineInterfaces = behaviorType + .GetInterfaces() + .Where(type => type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(IPipelineBehavior<,>)) + .ToList(); + + if (pipelineInterfaces.Count == 0) + { + var errorMessage = $"{behaviorType.Name} does not implement IPipelineBehavior<,>"; + _logger.Error(errorMessage); + throw new InvalidOperationException(errorMessage); + } + + // 为每个已闭合的管道接口建立显式映射,支持针对特定请求/响应的专用行为。 + foreach (var pipelineInterface in pipelineInterfaces) + { + GetServicesUnsafe.AddSingleton(pipelineInterface, behaviorType); + } + } + + _logger.Debug($"Mediator behavior registered: {behaviorType.Name}"); } finally {