Castle Windsor 3 Interceptor не выпускает компоненты, созданные типизированной фабрикой, а 2.5.4 -.Зачем? - PullRequest
3 голосов
/ 19 января 2012

Это аналогично тому, как указано в другом месте и подробно в этом блоге . У меня это работает с использованием 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 Ответ

2 голосов
/ 20 января 2012

Примечание для себя: - RTFM.Или, на самом деле, прочитайте файл Breakingchanges.txt.

Вот изменение, которое влияет на это поведение (выделение мое): -

change - Интерфейс IReleasePolicy имеет новый метод: IReleasePolicyCreateSubPolicy ();использование дополнительных политик изменяет способ, которым типизированные фабрики обрабатывают внеполосные выпуски компонентов (см. описание)

воздействие - средняя исправимость - легко

описание - это было добавлено как попыткавключить более детализированный анализ времени жизни (в основном для каждой типизированной фабрики прямо сейчас, но в будущем также скажем - для каждого окна в клиентском приложении).В качестве побочного эффекта этого (и изменения в поведении политики выпуска, описанного выше) больше нельзя выпускать объекты, разрешенные через типизированные фабрики, с использованием container.Release .Поскольку объекты теперь отслеживаются только в рамках фабрики, они будут освобождены, только если будет выполнен вызов к методу освобождения фабрики или когда сама фабрика выпущена.

fix - метод должен возвращать новый объект, которыйдемонстрирует то же поведение, что и «родительский», обычно лучше всего вернуть объект того же типа (как это делают встроенные политики выпуска).

Я не нашел ужасного предложения по исправлениюполезно в моем случае, однако мое решение в этом вопросе заключается в том, что вы должны делать (выпуск с использованием фабрики).Я оставлю это на всякий случай, если у кого-то еще есть эта (не) проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...