我正在调查应用程序中的内存泄漏。以下是上下文:
假设我需要处理不同类型的XML文件,并且每天会接收大量的XML文件,因此我有一个 IXmlProcessor
接口。
public interface IXmlProcessor
{
void ProcessXml(string xml);
}
还有一些具体的XML处理器。
public class UserXmlProcessor : IXmlProcessor
{
private readonly IUserRepository _userRepository;
public UserXmlProcessor(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void ProcessXml(string xml)
{
// do something with the xml
// call _userRepository
}
}
所有的IXmlProcessor
具体类型都已注册到 DI 容器中,为了解决它们的依赖,我有一个工厂类,也已注册到 DI 容器中,类似于下面的代码:
public class XmlProcessorFactory where TType : class
{
private readonly IServiceProvider _serviceProvider;
public XmlProcessorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IXmlProcessor GetImplementation(string identifier)
{
var type = FindType(identifier);
return _serviceProvider.GetService(type) as IXmlProcessor;
}
private Type FindType(string identifier)
{
// do some reflection to find the type based on the identifier (UserXmlProcessor, for example)
// don't worry, there's caching to avoid unecessary reflection
}
}
在某个时刻,我会召集他们所有人:
public class WorkItem
{
public string Identifier { get; set; }
public string Xml { get; set; }
}
public class WorkingClass
{
private readonly XmlProcessorFactory _xmlProcessorFactory;
public WorkingClass(XmlProcessorFactory xmlProcessorFactory)
{
_xmlProcessorFactory = xmlProcessorFactory;
}
public void DoWork(WorkItem item)
{
var processor = _xmlProcessorFactory.GetImplementation(item.Identifier);
processor.ProcessXml(item.Xml);
}
}
IUserRepository
是一个简单的实现,拥有Entity Framework上下文。
所以,这里有一个问题:根据微软的文档:
从容器中解析的服务不应由开发人员处理。
通过 DI 接收 IDisposable 依赖关系不需要接收方本身实现 IDisposable。IDisposable 依赖关系的接收者不应调用该依赖关系的 Dispose。
因此,如果我将 IUserRepository 注入到控制器中,那么可以,容器将处理对象的处理以及 EF Context 的处理,都不需要实现 IDisposable。
但是,我的 Xml Processors 怎么办?文档说:
未由服务容器创建的服务
开发人员负责释放服务。
避免使用服务定位器模式。例如,当您可以使用 DI 时,请勿调用 GetService 来获取服务实例。 另一个要避免的服务定位器变体是注入在运行时解析依赖项的工厂。这两种做法混合了控制反转策略。
并且 _ = serviceProvider.GetRequiredService<ExampleDisposable>();
是一种反模式。但是,正如您所看到的,我确实需要根据 XML 标识符在运行时解析依赖项,而且我不想采用 switch cases 的方式。
所以:
- 是否应让 IXmlProcessors 实现 IDisposable 并手动释放 IUserRepository?
- 是否应级联并使 IUserRepository 实现 IDisposable 以释放 EntityContext?
- 如果是这样,那会不会影响服务的生命周期,如果将其注入到控制器中?