【问题标题】:Castle Windsor 3 Interceptor not releasing components created by a typed factory but 2.5.4 did. Why?Castle Windsor 3 Interceptor 没有发布由类型化工厂创建的组件,但 2.5.4 发布了。为什么?
【发布时间】:2012-02-14 03:26:36
【问题描述】:

这与其他地方所述的模式相似,并详细说明了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) 方法,然后在它执行 handler.Process() 方法后,它显式释放处理程序实例,这似乎是作业 - 性能计数器上升,处理完成后下降)。

这里是工厂:

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

这是我的使用方法:

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

因此,明确地进行发布就不需要拦截器,但我真正的问题是,为什么发布之间的这种行为会有所不同?

【问题讨论】:

    标签: castle-windsor typed-factory-facility


    【解决方案1】:

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

    以下是影响此行为的更改(重点是我的):-

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

    影响 - 中等可修复性 - 容易

    description - 添加它是为了尝试更细粒度 生命周期范围(现在主要针对每个类型的工厂,但在 未来也说 - 客户端应用程序中的每个窗口)。作为那个的副作用 (并更改为上述发布策略行为)不是 不再可能释放通过类型化工厂解析的对象,使用 container.Release。由于现在仅在范围内跟踪对象 工厂的他们只有在致电工厂时才会被释放 释放方法,或者工厂本身释放时。

    fix - 方法应该返回具有相同行为的新对象 作为“父母”,通常最好返回相同的对象 类型(正如内置发布策略所做的那样)。

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

    【讨论】:

    • 如果它能让你感觉好些,我也会遇到同样的问题。
    • 我有这样的东西:Container.AddFacility(); Container.Register(Component.For().AsFactory().LifestyleTransient()); //文档docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx
    • 接口如下所示: public interface IServiceFactory { T Create();无效释放(对象服务); }
    • 嗨 Crazy Coder - 查看性能计数器,在我的情况下它似乎正在工作,而且我的开发平台已经运行了 4 天,内存使用量没有明显增加。相比之下,我发现了这个问题,因为该进程在运行一天后开始使用 900MB。我会用我的工厂和它的用法更新帖子。
    • 如果您使用构造函数或属性注入,并且不手动解析工厂,我认为 Windsor 将能够在您的依赖于工厂的服务被处置时正确处置所有组件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-20
    相关资源
    最近更新 更多