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}");
}