城堡温莎3拦截器不释放由类型工厂创建的组件,但2.5.4确实如此。为什么?

时间:2012-01-19 13:13:34

标签: castle-windsor typed-factory-facility

这与其他地方所述的模式类似,详细in this blog post。我有这个使用Windsor 2.5.4几乎与博文中所述,但决定切换到使用Windsor 3.当我这样做时,我注意到应用程序的内存使用量随着时间推移而上升 - 我猜这将是组件没有被释放。

博客帖子中的代码有一些修改,可能导致行为不同。

这是我的AutoRelease拦截器(直接出自博客帖子,这里是为了方便和懒惰;)

[Transient]
public class AutoReleaseHandlerInterceptor : IInterceptor
{
    private static readonly MethodInfo Execute = typeof(IDocumentHandler).GetMethod("Process");
    private readonly IKernel _kernel;
    public AutoReleaseHandlerInterceptor(IKernel kernel)
    {
        _kernel = kernel;
    }

    public void Intercept(IInvocation invocation)
    {
        if (invocation.Method != Execute)
        {
            invocation.Proceed();
            return;
        }
        try
        {
            invocation.Proceed();
        }
        finally
        {
            _kernel.ReleaseComponent(invocation.Proxy);
        }
    }
}

我对博客文章的偏见之一是打字工厂使用的选择器: -

public class ProcessorSelector : DefaultTypedFactoryComponentSelector
{
    protected override Func<IKernelInternal, IReleasePolicy, object> BuildFactoryComponent(MethodInfo method,
                                                                                           string componentName,
                                                                                           Type componentType,
                                                                                           IDictionary additionalArguments)
    {
        return new MyDocumentHandlerResolver(componentName,
            componentType,
            additionalArguments,
            FallbackToResolveByTypeIfNameNotFound,
            GetType()).Resolve;
    }
    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        return null;
    }
    protected override Type GetComponentType(MethodInfo method, object[] arguments)
    {
        var message = arguments[0];
        var handlerType = typeof(IDocumentHandler<>).MakeGenericType(message.GetType());
        return handlerType;
    }
}

值得注意的是我不使用默认的解析器。 (这可能是问题所在......)。

public class MyDocumentHandlerResolver : TypedFactoryComponentResolver
{

    public override object Resolve(IKernelInternal kernel, IReleasePolicy scope)
    {
        return kernel.Resolve(componentType, additionalArguments, scope);
    }
}

(为了简洁,我省略了ctor-没有什么特别的事发生,它只是调用基地ctor。)

我这样做的原因是因为默认的解析器会尝试按名称解析而不是按类型解析而失败。在这种情况下,我知道我只需要按类型解析,所以我只是覆盖了Resolve方法。

最后一块拼图将是安装人员。

container.AddFacility<TypedFactoryFacility>()
         .Register(
          Component.For<AutoReleaseHandlerInterceptor>(),
          Component.For<ProcessorSelector>().ImplementedBy<ProcessorSelector>(),
          Classes.FromAssemblyContaining<MessageHandler>()
                 .BasedOn(typeof(IDocumentHandler<>))
                 .WithService.Base()
                 .Configure(c => c.LifeStyle.Is(LifestyleType.Transient)),
          Component.For<IDocumentHandlerFactory>()
                   .AsFactory(c => c.SelectedWith<ProcessorSelector>()));

单步执行代码,调用拦截器 并执行finally子句(例如,我没有得到方法名称错误)。但是,组件似乎没有被释放(使用性能计数器显示这一点。每次调用工厂的create方法都会将计数器增加一个。)

到目前为止,我的解决方法是将void Release(IDocumentHandler处理程序)方法添加到我的工厂接口,然后在执行handler.Process()方法之后,它显式释放处理程序实例,这似乎做了工作 - 性能计数器上升,并且随着处理完成,它会下降)。

这是工厂:

public interface IDocumentHandlerFactory
{
    IDocumentHandler GetHandlerForDocument(IDocument document);
    void Release(IDocumentHandler handler);
}

以下是我如何使用它:

IDocumentHandlerFactory handler = _documentHandlerFactory.GetHandlerForDocument(document);
handler.Process();
_documentHandlerFactory.Release(handler);

明确地执行Release会消除对拦截器的需求,但我真正的问题是为什么这些行为在发行版之间有所不同?

1 个答案:

答案 0 :(得分:2)

自我注意: - RTFM。或者实际上,请阅读Breakingchanges.txt文件。

这是影响这种行为的变化(重点是我的): -

  

更改 - IReleasePolicy接口有一个新方法:IReleasePolicy   CreateSubPolicy();子策略的使用改变了类型化工厂的方式   处理组件的带外释放(见说明)

     

影响 - 中等可修复性 - 简单

     

description - 这是为了尝试实现更细粒度而添加的   终生范围(现在主要针对每个类型的工厂,但在   未来也会说 - 客户端应用程序中的每个窗口)。作为副作用   (并更改为上述发布策略行为) 不是   使用可以更长时间释放通过类型化工厂解析的对象   container.Release 即可。因为现在仅在范围内跟踪对象   他们只有在打电话给工厂才会被释放   发布方法,或工厂本身被释放。

     

fix - Method应该返回暴露相同行为的新对象   作为“父”通常最好返回相同的对象   type(作为内置的发布策略)。

我没有在我的实例中发现修复建议非常有用,但我在问题中的解决方案是你应该做的事情(使用工厂发布)。如果其他人有这个(非)问题,我会把它留下来。