我正在运行一个ISAPI服务,该服务使用IdHTTPWebBrokerBridge
运行(用于作为独立的EXE进行调试)以及运行mod_isapi
的Apache(在生产环境中)。
在破坏Web模块时记录一些内容时,我发现了以下问题:
unit LogFactory;
...
initialization
GlobalLogFactory := TMyLogFactory.Create;
finalization
FreeAndNil(GlobalLogFactory);
end.
-
unit MyWebModuleUnit;
...
uses LogFactory;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
Assert(Assigned(GlobalLogFactory)); // <-- failure
GlobalLogFactory.GetLogger('D:\test.txt').LogLine('test'); // <-- Nullpointer Exception
end;
LogFactory.pas
在初始化时创建对象GlobalLogFactory
并在其最终确定时销毁它。
但是LogFactory.pas:finalization
被称为TMyWebModule.WebModuleDestroy
,因为它仅包含在此单元中,因此最终确定将以相反的顺序进行。
如何确保我的GlobalLogFactory
被正确释放(即FastMM不会警告内存泄漏),但与此同时,我想让所有销毁/终结程序都有机会记录什么?
一种解决方法是将LogFactory.pas
明确地包含在DPR文件中作为第一个单元。但是我不太喜欢这个,因为这个日志单元应该在很多项目中使用,只需将它包含在你需要记录的单元中就可以使用它。将此日志单元放在可能希望将来记录某些内容的每个DPR中是一项很大的工作,如果忘记它可能会给那些不知道我做了什么/需要的开发人员带来问题。
答案 0 :(得分:2)
不使用全局变量中的类实例,而是使用接口和函数来获取它。
unit LogFactory;
interface
type
ILogFactory = interface
[{GUID}]
function GetLogger(...) : TLogger;
...
end;
TLogFactory = class( TInterfacedObject, ILogFactory )
function GetLogger(...) : TLogger;
end;
function GlobalLogFactory : ILogFactory;
implementation
var
_LogFactory : ILogFactory;
function GlobalLogFactory : ILogFactory;
begin
if not Assigned( _LogFactory ) then
_LogFactory := TLogFactory.Create;
Result := _LogFactory;
end;
{ TLogFactory Implementation }
initialization
// nothing needed
finalization
// nothing needed
end.
根本不需要任何initialization
或finalization
。
答案 1 :(得分:0)
如果你想要
如果你仍然不能这样做,那么我会看到另一种选择。安排记录器初始化在代码中的任何其他初始化之前发生。所有其他定稿后的最终确定。您可以通过将记录器实现放入与加载时链接链接的外部模块来实现。