From bb2b3a0c60e70f936eaf76532d14ca9a3b60f095 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sun, 5 Apr 2026 11:01:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(arch):=20=E9=87=8D=E6=9E=84=E6=9E=B6?= =?UTF-8?q?=E6=9E=84=E7=BB=84=E4=BB=B6=E6=B3=A8=E5=86=8C=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将组件注册逻辑提取到独立的 ArchitectureComponentRegistry 类中 - 实现 ArchitectureComponentActivator 来支持注册阶段实例化组件 - 更新系统和模型注册文档说明,明确在注册阶段创建实例并参与初始化 - 修复类型注册在架构准备就绪后的行为一致性问题 - 添加完整的组件注册行为测试覆盖实例注册、工厂注册和生命周期管理 - 优化依赖注入解析机制,支持构造函数依赖和单例缓存 --- ...hitectureComponentRegistryBehaviorTests.cs | 170 +++++++++++++++++- GFramework.Core/Architectures/Architecture.cs | 5 +- .../ArchitectureComponentActivator.cs | 94 ++++++++++ .../ArchitectureComponentRegistry.cs | 47 ++--- 4 files changed, 281 insertions(+), 35 deletions(-) create mode 100644 GFramework.Core/Architectures/ArchitectureComponentActivator.cs diff --git a/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs b/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs index 74344191..fba37f01 100644 --- a/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs +++ b/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs @@ -122,6 +122,62 @@ public class ArchitectureComponentRegistryBehaviorTests await architecture.DestroyAsync(); } + /// + /// 验证系统类型注册会在初始化期间物化实例、注入构造函数依赖并执行创建回调。 + /// + [Test] + public async Task RegisterSystem_Type_Should_Create_Instance_During_Initialization() + { + var dependency = new ConstructorDependency("system-dependency"); + FactoryCreatedSystem? callbackInstance = null; + var architecture = new RegistryTestArchitecture( + target => target.RegisterSystem(created => callbackInstance = created), + services => services.AddSingleton(dependency)); + + await architecture.InitializeAsync(); + + var resolved = architecture.Context.GetSystem(); + + Assert.Multiple(() => + { + Assert.That(callbackInstance, Is.Not.Null); + Assert.That(resolved, Is.SameAs(callbackInstance)); + Assert.That(resolved.Dependency, Is.SameAs(dependency)); + Assert.That(resolved.GetContext(), Is.SameAs(architecture.Context)); + Assert.That(resolved.InitializeCallCount, Is.EqualTo(1)); + }); + + await architecture.DestroyAsync(); + } + + /// + /// 验证模型类型注册会在初始化期间物化实例、注入构造函数依赖并执行创建回调。 + /// + [Test] + public async Task RegisterModel_Type_Should_Create_Instance_During_Initialization() + { + var dependency = new ConstructorDependency("model-dependency"); + FactoryCreatedModel? callbackInstance = null; + var architecture = new RegistryTestArchitecture( + target => target.RegisterModel(created => callbackInstance = created), + services => services.AddSingleton(dependency)); + + await architecture.InitializeAsync(); + + var resolved = architecture.Context.GetModel(); + + Assert.Multiple(() => + { + Assert.That(callbackInstance, Is.Not.Null); + Assert.That(resolved, Is.SameAs(callbackInstance)); + Assert.That(resolved.Dependency, Is.SameAs(dependency)); + Assert.That(resolved.GetContext(), Is.SameAs(architecture.Context)); + Assert.That(resolved.InitializeCallCount, Is.EqualTo(1)); + }); + + await architecture.DestroyAsync(); + } + /// /// 验证 Ready 阶段后不允许继续注册 Utility,保持与系统和模型一致的约束。 /// @@ -142,14 +198,35 @@ public class ArchitectureComponentRegistryBehaviorTests /// /// 用于测试组件注册行为的最小架构实现。 /// - private sealed class RegistryTestArchitecture(Action registrationAction) : Architecture + private sealed class RegistryTestArchitecture : Architecture { + private readonly Action? _configurator; + private readonly Action _registrationAction; + + /// + /// 创建一个可选地附带服务配置逻辑的测试架构。 + /// + /// 初始化阶段执行的组件注册逻辑。 + /// 初始化前执行的服务配置逻辑。 + public RegistryTestArchitecture( + Action registrationAction, + Action? configurator = null) + { + _registrationAction = registrationAction; + _configurator = configurator; + } + + /// + /// 返回测试注入的服务配置逻辑。 + /// + public override Action? Configurator => _configurator; + /// /// 在初始化阶段执行测试注入的注册逻辑。 /// protected override void OnInitialize() { - registrationAction(this); + _registrationAction(this); } } @@ -303,4 +380,93 @@ public class ArchitectureComponentRegistryBehaviorTests private sealed class FactoryCreatedUtility : IUtility { } + + /// + /// 用于验证构造函数依赖注入的简单依赖对象。 + /// + private sealed class ConstructorDependency(string name) + { + /// + /// 获取依赖对象名称。 + /// + public string Name { get; } = name; + } + + /// + /// 用于验证系统类型注册路径的工厂创建系统。 + /// + private sealed class FactoryCreatedSystem(ConstructorDependency dependency) : ISystem + { + private IArchitectureContext _context = null!; + + /// + /// 获取构造函数注入的依赖对象。 + /// + public ConstructorDependency Dependency { get; } = dependency; + + /// + /// 获取初始化调用次数。 + /// + public int InitializeCallCount { get; private set; } + + public void Initialize() + { + InitializeCallCount++; + } + + public void Destroy() + { + } + + public void OnArchitecturePhase(ArchitecturePhase phase) + { + } + + public void SetContext(IArchitectureContext context) + { + _context = context; + } + + public IArchitectureContext GetContext() + { + return _context; + } + } + + /// + /// 用于验证模型类型注册路径的工厂创建模型。 + /// + private sealed class FactoryCreatedModel(ConstructorDependency dependency) : IModel + { + private IArchitectureContext _context = null!; + + /// + /// 获取构造函数注入的依赖对象。 + /// + public ConstructorDependency Dependency { get; } = dependency; + + /// + /// 获取初始化调用次数。 + /// + 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; + } + } } \ No newline at end of file diff --git a/GFramework.Core/Architectures/Architecture.cs b/GFramework.Core/Architectures/Architecture.cs index af96d03f..ff12d133 100644 --- a/GFramework.Core/Architectures/Architecture.cs +++ b/GFramework.Core/Architectures/Architecture.cs @@ -7,7 +7,6 @@ using GFramework.Core.Abstractions.Systems; using GFramework.Core.Abstractions.Utility; using GFramework.Core.Environment; using GFramework.Core.Logging; -using Microsoft.Extensions.DependencyInjection; namespace GFramework.Core.Architectures; @@ -182,7 +181,7 @@ public abstract class Architecture : IArchitecture } /// - /// 注册系统类型,由 DI 容器自动创建实例 + /// 注册系统类型,由当前服务集合自动创建实例并接入本轮初始化 /// /// 系统类型 /// 可选的实例创建后回调 @@ -203,7 +202,7 @@ public abstract class Architecture : IArchitecture } /// - /// 注册模型类型,由 DI 容器自动创建实例 + /// 注册模型类型,由当前服务集合自动创建实例并接入本轮初始化 /// /// 模型类型 /// 可选的实例创建后回调 diff --git a/GFramework.Core/Architectures/ArchitectureComponentActivator.cs b/GFramework.Core/Architectures/ArchitectureComponentActivator.cs new file mode 100644 index 00000000..3c2b3c80 --- /dev/null +++ b/GFramework.Core/Architectures/ArchitectureComponentActivator.cs @@ -0,0 +1,94 @@ +using GFramework.Core.Abstractions.Ioc; +using GFramework.Core.Abstractions.Logging; + +namespace GFramework.Core.Architectures; + +/// +/// 为架构组件的类型注册路径提供实例创建能力。 +/// 该类型在容器冻结前基于当前服务集合和已注册实例进行激活, +/// 使 可以在注册阶段就物化 System / Model, +/// 避免它们在 Ready 之后首次解析时才参与生命周期而导致状态不一致。 +/// +internal sealed class ArchitectureComponentActivator( + IIocContainer container, + ILogger logger) +{ + /// + /// 根据当前容器状态创建组件实例。 + /// 激活过程优先复用已经注册到容器中的实例,再按服务描述解析实现类型或工厂方法, + /// 以兼容构造函数依赖于框架服务、用户实例服务和先前注册组件的场景。 + /// + /// 要创建的组件类型。 + /// 创建完成的组件实例。 + public TComponent CreateInstance() where TComponent : class + { + var activationProvider = new RegistrationServiceProvider(container, logger); + return ActivatorUtilities.CreateInstance(activationProvider); + } + + /// + /// 面向组件注册的轻量级服务提供者。 + /// 该实现只覆盖预冻结阶段需要的解析能力,避免引入完整容器冻结过程。 + /// + private sealed class RegistrationServiceProvider( + IIocContainer container, + ILogger logger) : IServiceProvider + { + private readonly Dictionary _singletonCache = []; + + /// + /// 从当前服务集合中解析指定类型的服务。 + /// 解析顺序为:已注册实例 → 服务描述实例/工厂/实现类型 → 可直接实例化的具体类型。 + /// + /// 请求解析的服务类型。 + /// 解析到的服务实例;若无法解析则返回 null。 + public object? GetService(Type serviceType) + { + if (serviceType == typeof(IServiceProvider)) + return this; + + var existingInstance = container.Get(serviceType); + if (existingInstance != null) + return existingInstance; + + var descriptor = + container.GetServicesUnsafe.LastOrDefault(candidate => candidate.ServiceType == serviceType); + if (descriptor != null) + return ResolveDescriptor(serviceType, descriptor); + + if (!serviceType.IsAbstract && !serviceType.IsInterface) + return ActivatorUtilities.CreateInstance(this, serviceType); + + logger.Trace($"Activation provider could not resolve {serviceType.Name}"); + return null; + } + + /// + /// 根据服务描述解析实例,并对单例描述进行缓存。 + /// 这样可以保证同一类型在一次组件注册流程中只创建一次依赖实例。 + /// + /// 请求的服务类型。 + /// 命中的服务描述。 + /// 解析到的实例。 + private object? ResolveDescriptor(Type requestedType, ServiceDescriptor descriptor) + { + if (descriptor.Lifetime == ServiceLifetime.Singleton && + _singletonCache.TryGetValue(requestedType, out var cached)) + return cached; + + object? resolved = descriptor switch + { + { ImplementationInstance: not null } => descriptor.ImplementationInstance, + { ImplementationFactory: not null } => descriptor.ImplementationFactory(this), + { ImplementationType: not null } => ActivatorUtilities.CreateInstance(this, + descriptor.ImplementationType), + _ => null + }; + + if (descriptor.Lifetime == ServiceLifetime.Singleton && resolved != null) + _singletonCache[requestedType] = resolved; + + return resolved; + } + } +} \ No newline at end of file diff --git a/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs b/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs index 91b2a846..9925d533 100644 --- a/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs +++ b/GFramework.Core/Architectures/ArchitectureComponentRegistry.cs @@ -5,7 +5,6 @@ using GFramework.Core.Abstractions.Model; using GFramework.Core.Abstractions.Systems; using GFramework.Core.Abstractions.Utility; using GFramework.Core.Extensions; -using Microsoft.Extensions.DependencyInjection; namespace GFramework.Core.Architectures; @@ -20,6 +19,8 @@ internal sealed class ArchitectureComponentRegistry( ArchitectureLifecycle lifecycle, ILogger logger) { + private readonly ArchitectureComponentActivator _activator = new(services.Container, logger); + #region Validation /// @@ -63,7 +64,8 @@ internal sealed class ArchitectureComponentRegistry( } /// - /// 注册系统类型,由 DI 容器自动创建实例 + /// 注册系统类型,并在注册阶段由当前服务集合立即创建实例。 + /// 这样可以确保该系统参与当前架构初始化批次,而不是等到 Ready 之后首次解析时才延迟创建。 /// /// 系统类型 /// 可选的实例创建后回调 @@ -72,21 +74,12 @@ internal sealed class ArchitectureComponentRegistry( ValidateRegistration("system"); logger.Debug($"Registering system type: {typeof(T).Name}"); - services.Container.RegisterFactory(sp => - { - // 1. DI 创建实例 - var system = ActivatorUtilities.CreateInstance(sp); - - // 2. 框架默认处理 - system.SetContext(architecture.Context); - lifecycle.RegisterLifecycleComponent(system); - - // 3. 用户自定义处理(钩子) - onCreated?.Invoke(system); - - logger.Debug($"System created: {typeof(T).Name}"); - return system; - }); + // 类型注册路径在注册阶段就物化实例,确保组件能参与当前初始化批次。 + var system = _activator.CreateInstance(); + system.SetContext(architecture.Context); + lifecycle.RegisterLifecycleComponent(system); + onCreated?.Invoke(system); + services.Container.RegisterPlurality(system); logger.Info($"System type registered: {typeof(T).Name}"); } @@ -118,7 +111,8 @@ internal sealed class ArchitectureComponentRegistry( } /// - /// 注册模型类型,由 DI 容器自动创建实例 + /// 注册模型类型,并在注册阶段由当前服务集合立即创建实例。 + /// 这样可以确保该模型参与当前架构初始化批次,而不是等到 Ready 之后首次解析时才延迟创建。 /// /// 模型类型 /// 可选的实例创建后回调 @@ -127,18 +121,11 @@ internal sealed class ArchitectureComponentRegistry( ValidateRegistration("model"); logger.Debug($"Registering model type: {typeof(T).Name}"); - services.Container.RegisterFactory(sp => - { - var model = ActivatorUtilities.CreateInstance(sp); - model.SetContext(architecture.Context); - lifecycle.RegisterLifecycleComponent(model); - - // 用户自定义钩子 - onCreated?.Invoke(model); - - logger.Debug($"Model created: {typeof(T).Name}"); - return model; - }); + var model = _activator.CreateInstance(); + model.SetContext(architecture.Context); + lifecycle.RegisterLifecycleComponent(model); + onCreated?.Invoke(model); + services.Container.RegisterPlurality(model); logger.Info($"Model type registered: {typeof(T).Name}"); }