mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-11 12:14:30 +08:00
refactor(arch): 重构架构组件注册机制
- 将组件注册逻辑提取到独立的 ArchitectureComponentRegistry 类中 - 实现 ArchitectureComponentActivator 来支持注册阶段实例化组件 - 更新系统和模型注册文档说明,明确在注册阶段创建实例并参与初始化 - 修复类型注册在架构准备就绪后的行为一致性问题 - 添加完整的组件注册行为测试覆盖实例注册、工厂注册和生命周期管理 - 优化依赖注入解析机制,支持构造函数依赖和单例缓存
This commit is contained in:
parent
01dc1523a5
commit
bb2b3a0c60
@ -122,6 +122,62 @@ public class ArchitectureComponentRegistryBehaviorTests
|
|||||||
await architecture.DestroyAsync();
|
await architecture.DestroyAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证系统类型注册会在初始化期间物化实例、注入构造函数依赖并执行创建回调。
|
||||||
|
/// </summary>
|
||||||
|
[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<FactoryCreatedSystem>(created => callbackInstance = created),
|
||||||
|
services => services.AddSingleton(dependency));
|
||||||
|
|
||||||
|
await architecture.InitializeAsync();
|
||||||
|
|
||||||
|
var resolved = architecture.Context.GetSystem<FactoryCreatedSystem>();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证模型类型注册会在初始化期间物化实例、注入构造函数依赖并执行创建回调。
|
||||||
|
/// </summary>
|
||||||
|
[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<FactoryCreatedModel>(created => callbackInstance = created),
|
||||||
|
services => services.AddSingleton(dependency));
|
||||||
|
|
||||||
|
await architecture.InitializeAsync();
|
||||||
|
|
||||||
|
var resolved = architecture.Context.GetModel<FactoryCreatedModel>();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证 Ready 阶段后不允许继续注册 Utility,保持与系统和模型一致的约束。
|
/// 验证 Ready 阶段后不允许继续注册 Utility,保持与系统和模型一致的约束。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -142,14 +198,35 @@ public class ArchitectureComponentRegistryBehaviorTests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于测试组件注册行为的最小架构实现。
|
/// 用于测试组件注册行为的最小架构实现。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private sealed class RegistryTestArchitecture(Action<RegistryTestArchitecture> registrationAction) : Architecture
|
private sealed class RegistryTestArchitecture : Architecture
|
||||||
{
|
{
|
||||||
|
private readonly Action<IServiceCollection>? _configurator;
|
||||||
|
private readonly Action<RegistryTestArchitecture> _registrationAction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建一个可选地附带服务配置逻辑的测试架构。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="registrationAction">初始化阶段执行的组件注册逻辑。</param>
|
||||||
|
/// <param name="configurator">初始化前执行的服务配置逻辑。</param>
|
||||||
|
public RegistryTestArchitecture(
|
||||||
|
Action<RegistryTestArchitecture> registrationAction,
|
||||||
|
Action<IServiceCollection>? configurator = null)
|
||||||
|
{
|
||||||
|
_registrationAction = registrationAction;
|
||||||
|
_configurator = configurator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回测试注入的服务配置逻辑。
|
||||||
|
/// </summary>
|
||||||
|
public override Action<IServiceCollection>? Configurator => _configurator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在初始化阶段执行测试注入的注册逻辑。
|
/// 在初始化阶段执行测试注入的注册逻辑。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void OnInitialize()
|
protected override void OnInitialize()
|
||||||
{
|
{
|
||||||
registrationAction(this);
|
_registrationAction(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,4 +380,93 @@ public class ArchitectureComponentRegistryBehaviorTests
|
|||||||
private sealed class FactoryCreatedUtility : IUtility
|
private sealed class FactoryCreatedUtility : IUtility
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于验证构造函数依赖注入的简单依赖对象。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class ConstructorDependency(string name)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取依赖对象名称。
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; } = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于验证系统类型注册路径的工厂创建系统。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class FactoryCreatedSystem(ConstructorDependency dependency) : ISystem
|
||||||
|
{
|
||||||
|
private IArchitectureContext _context = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取构造函数注入的依赖对象。
|
||||||
|
/// </summary>
|
||||||
|
public ConstructorDependency Dependency { get; } = dependency;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取初始化调用次数。
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于验证模型类型注册路径的工厂创建模型。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class FactoryCreatedModel(ConstructorDependency dependency) : IModel
|
||||||
|
{
|
||||||
|
private IArchitectureContext _context = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取构造函数注入的依赖对象。
|
||||||
|
/// </summary>
|
||||||
|
public ConstructorDependency Dependency { get; } = dependency;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取初始化调用次数。
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -7,7 +7,6 @@ using GFramework.Core.Abstractions.Systems;
|
|||||||
using GFramework.Core.Abstractions.Utility;
|
using GFramework.Core.Abstractions.Utility;
|
||||||
using GFramework.Core.Environment;
|
using GFramework.Core.Environment;
|
||||||
using GFramework.Core.Logging;
|
using GFramework.Core.Logging;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace GFramework.Core.Architectures;
|
namespace GFramework.Core.Architectures;
|
||||||
|
|
||||||
@ -182,7 +181,7 @@ public abstract class Architecture : IArchitecture
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册系统类型,由 DI 容器自动创建实例
|
/// 注册系统类型,由当前服务集合自动创建实例并接入本轮初始化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">系统类型</typeparam>
|
/// <typeparam name="T">系统类型</typeparam>
|
||||||
/// <param name="onCreated">可选的实例创建后回调</param>
|
/// <param name="onCreated">可选的实例创建后回调</param>
|
||||||
@ -203,7 +202,7 @@ public abstract class Architecture : IArchitecture
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册模型类型,由 DI 容器自动创建实例
|
/// 注册模型类型,由当前服务集合自动创建实例并接入本轮初始化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">模型类型</typeparam>
|
/// <typeparam name="T">模型类型</typeparam>
|
||||||
/// <param name="onCreated">可选的实例创建后回调</param>
|
/// <param name="onCreated">可选的实例创建后回调</param>
|
||||||
|
|||||||
@ -0,0 +1,94 @@
|
|||||||
|
using GFramework.Core.Abstractions.Ioc;
|
||||||
|
using GFramework.Core.Abstractions.Logging;
|
||||||
|
|
||||||
|
namespace GFramework.Core.Architectures;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为架构组件的类型注册路径提供实例创建能力。
|
||||||
|
/// 该类型在容器冻结前基于当前服务集合和已注册实例进行激活,
|
||||||
|
/// 使 <see cref="ArchitectureComponentRegistry" /> 可以在注册阶段就物化 System / Model,
|
||||||
|
/// 避免它们在 Ready 之后首次解析时才参与生命周期而导致状态不一致。
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class ArchitectureComponentActivator(
|
||||||
|
IIocContainer container,
|
||||||
|
ILogger logger)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 根据当前容器状态创建组件实例。
|
||||||
|
/// 激活过程优先复用已经注册到容器中的实例,再按服务描述解析实现类型或工厂方法,
|
||||||
|
/// 以兼容构造函数依赖于框架服务、用户实例服务和先前注册组件的场景。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">要创建的组件类型。</typeparam>
|
||||||
|
/// <returns>创建完成的组件实例。</returns>
|
||||||
|
public TComponent CreateInstance<TComponent>() where TComponent : class
|
||||||
|
{
|
||||||
|
var activationProvider = new RegistrationServiceProvider(container, logger);
|
||||||
|
return ActivatorUtilities.CreateInstance<TComponent>(activationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 面向组件注册的轻量级服务提供者。
|
||||||
|
/// 该实现只覆盖预冻结阶段需要的解析能力,避免引入完整容器冻结过程。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class RegistrationServiceProvider(
|
||||||
|
IIocContainer container,
|
||||||
|
ILogger logger) : IServiceProvider
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Type, object?> _singletonCache = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从当前服务集合中解析指定类型的服务。
|
||||||
|
/// 解析顺序为:已注册实例 → 服务描述实例/工厂/实现类型 → 可直接实例化的具体类型。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceType">请求解析的服务类型。</param>
|
||||||
|
/// <returns>解析到的服务实例;若无法解析则返回 null。</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据服务描述解析实例,并对单例描述进行缓存。
|
||||||
|
/// 这样可以保证同一类型在一次组件注册流程中只创建一次依赖实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestedType">请求的服务类型。</param>
|
||||||
|
/// <param name="descriptor">命中的服务描述。</param>
|
||||||
|
/// <returns>解析到的实例。</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,6 @@ using GFramework.Core.Abstractions.Model;
|
|||||||
using GFramework.Core.Abstractions.Systems;
|
using GFramework.Core.Abstractions.Systems;
|
||||||
using GFramework.Core.Abstractions.Utility;
|
using GFramework.Core.Abstractions.Utility;
|
||||||
using GFramework.Core.Extensions;
|
using GFramework.Core.Extensions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace GFramework.Core.Architectures;
|
namespace GFramework.Core.Architectures;
|
||||||
|
|
||||||
@ -20,6 +19,8 @@ internal sealed class ArchitectureComponentRegistry(
|
|||||||
ArchitectureLifecycle lifecycle,
|
ArchitectureLifecycle lifecycle,
|
||||||
ILogger logger)
|
ILogger logger)
|
||||||
{
|
{
|
||||||
|
private readonly ArchitectureComponentActivator _activator = new(services.Container, logger);
|
||||||
|
|
||||||
#region Validation
|
#region Validation
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -63,7 +64,8 @@ internal sealed class ArchitectureComponentRegistry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册系统类型,由 DI 容器自动创建实例
|
/// 注册系统类型,并在注册阶段由当前服务集合立即创建实例。
|
||||||
|
/// 这样可以确保该系统参与当前架构初始化批次,而不是等到 Ready 之后首次解析时才延迟创建。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">系统类型</typeparam>
|
/// <typeparam name="T">系统类型</typeparam>
|
||||||
/// <param name="onCreated">可选的实例创建后回调</param>
|
/// <param name="onCreated">可选的实例创建后回调</param>
|
||||||
@ -72,21 +74,12 @@ internal sealed class ArchitectureComponentRegistry(
|
|||||||
ValidateRegistration("system");
|
ValidateRegistration("system");
|
||||||
logger.Debug($"Registering system type: {typeof(T).Name}");
|
logger.Debug($"Registering system type: {typeof(T).Name}");
|
||||||
|
|
||||||
services.Container.RegisterFactory<T>(sp =>
|
// 类型注册路径在注册阶段就物化实例,确保组件能参与当前初始化批次。
|
||||||
{
|
var system = _activator.CreateInstance<T>();
|
||||||
// 1. DI 创建实例
|
system.SetContext(architecture.Context);
|
||||||
var system = ActivatorUtilities.CreateInstance<T>(sp);
|
lifecycle.RegisterLifecycleComponent(system);
|
||||||
|
onCreated?.Invoke(system);
|
||||||
// 2. 框架默认处理
|
services.Container.RegisterPlurality(system);
|
||||||
system.SetContext(architecture.Context);
|
|
||||||
lifecycle.RegisterLifecycleComponent(system);
|
|
||||||
|
|
||||||
// 3. 用户自定义处理(钩子)
|
|
||||||
onCreated?.Invoke(system);
|
|
||||||
|
|
||||||
logger.Debug($"System created: {typeof(T).Name}");
|
|
||||||
return system;
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.Info($"System type registered: {typeof(T).Name}");
|
logger.Info($"System type registered: {typeof(T).Name}");
|
||||||
}
|
}
|
||||||
@ -118,7 +111,8 @@ internal sealed class ArchitectureComponentRegistry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注册模型类型,由 DI 容器自动创建实例
|
/// 注册模型类型,并在注册阶段由当前服务集合立即创建实例。
|
||||||
|
/// 这样可以确保该模型参与当前架构初始化批次,而不是等到 Ready 之后首次解析时才延迟创建。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">模型类型</typeparam>
|
/// <typeparam name="T">模型类型</typeparam>
|
||||||
/// <param name="onCreated">可选的实例创建后回调</param>
|
/// <param name="onCreated">可选的实例创建后回调</param>
|
||||||
@ -127,18 +121,11 @@ internal sealed class ArchitectureComponentRegistry(
|
|||||||
ValidateRegistration("model");
|
ValidateRegistration("model");
|
||||||
logger.Debug($"Registering model type: {typeof(T).Name}");
|
logger.Debug($"Registering model type: {typeof(T).Name}");
|
||||||
|
|
||||||
services.Container.RegisterFactory<T>(sp =>
|
var model = _activator.CreateInstance<T>();
|
||||||
{
|
model.SetContext(architecture.Context);
|
||||||
var model = ActivatorUtilities.CreateInstance<T>(sp);
|
lifecycle.RegisterLifecycleComponent(model);
|
||||||
model.SetContext(architecture.Context);
|
onCreated?.Invoke(model);
|
||||||
lifecycle.RegisterLifecycleComponent(model);
|
services.Container.RegisterPlurality(model);
|
||||||
|
|
||||||
// 用户自定义钩子
|
|
||||||
onCreated?.Invoke(model);
|
|
||||||
|
|
||||||
logger.Debug($"Model created: {typeof(T).Name}");
|
|
||||||
return model;
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.Info($"Model type registered: {typeof(T).Name}");
|
logger.Info($"Model type registered: {typeof(T).Name}");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user