Spring4D依赖注入结合MVP架构时循环创建实例问题求助
Spring4D 解决MVP循环依赖问题
问题原因分析
你当前的代码存在循环依赖死循环:
- 视图在
FormCreate中主动解析IConversorService(Presenter) - Presenter的构造函数依赖注入
IConversorView(视图) - 虽然视图注册了单例,但如果视图是手动通过
Application.CreateForm创建的,容器中的单例实例和当前运行的视图实例是两个独立对象。容器解析Presenter时,会创建新的视图单例,新视图又会触发解析Presenter,最终陷入循环。 - 即便视图由容器创建,构造函数注入的循环依赖也会导致容器无法完成对象初始化——创建Presenter需要视图,创建视图需要Presenter,形成死锁。
Spring4D完全支持这种MVP场景,只需调整依赖注入的方式或实例管理逻辑即可解决。
解决方案
方案1:属性注入替代构造函数注入(推荐)
通过属性注入避免构造函数层面的循环依赖,让容器在对象创建后完成依赖注入:
1. 修改Presenter代码
Type TConversorService = Class(TInterfacedObject, IConversorService) Private [Inject] // 标记为需要注入的属性 FView: IConversorView; [Inject] FUseCase: IConversorUseCase; Public Constructor Create; // 移除构造函数的依赖参数 End; implementation Constructor TConversorService.Create; begin inherited; // 容器会在实例创建后自动注入FView和FUseCase end;
2. 修改视图代码
type TfrmConversorView = class(TForm, IConversorView) JvStatusBar1: TJvStatusBar; procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); private [Inject] // 标记为需要注入的属性 FService: IConversorService; public end; ... procedure TfrmConversorView.FormCreate(Sender: TObject); begin // 移除手动Resolve,调用容器完成属性注入 GlobalContainer.Inject(Self); end;
3. 调整容器注册
procedure RegisterTypes(const Container: TContainer); begin Container.RegisterType<TConexao>.asSingleton; // 显式声明实现的接口,提升代码可读性 Container.RegisterType<TConversorService>.Implements<IConversorService>; Container.RegisterType<TfrmConversorView>.AsSingleton.Implements<IConversorView>; Container.RegisterType<TConversorUseCase>.Implements<IConversorUseCase>; container.Build; end;
方案2:手动注册已创建的视图实例
如果必须保留构造函数注入,且视图是手动创建的,需将已创建的视图实例注册到容器,确保容器解析IConversorView时使用现有实例:
1. 修改视图的FormCreate
procedure TfrmConversorView.FormCreate(Sender: TObject); begin // 将当前视图实例注册为单例,覆盖之前的类型注册 GlobalContainer.RegisterInstance<IConversorView>(Self).AsSingleton; // 再解析Presenter FService := GlobalContainer.Resolve<IConversorService>; end;
2. 调整容器注册
procedure RegisterTypes(const Container: TContainer); begin Container.RegisterType<TConexao>.asSingleton; Container.RegisterType<TConversorService>.Implements<IConversorService>; // 移除视图的类型注册,避免冲突 // Container.RegisterType<TfrmConversorView>.AsSingleton(); Container.RegisterType<TConversorUseCase>.Implements<IConversorUseCase>; container.Build; end;
方案3:由容器创建视图实例
让容器负责创建视图,替代手动Application.CreateForm,容器可自动跟踪实例并处理依赖:
1. 程序入口修改
program ConversorApp; uses Vcl.Forms, Spring.Container, YourUnit in 'YourUnit.pas'; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; RegisterTypes(GlobalContainer); // 由容器解析视图实例,自动完成依赖注入 Application.MainForm := GlobalContainer.Resolve<TfrmConversorView>; Application.Run; GlobalContainer.Free; end.
2. 视图FormCreate简化
procedure TfrmConversorView.FormCreate(Sender: TObject); begin // 无需手动Resolve,容器已通过属性注入完成FService赋值 end;
内容的提问来源于stack exchange,提问作者Marcelo Borgues
相关产品推荐
相关产品推荐

