Поддерживает ли Spring.NET создание времени жизни пользовательских объектов? - PullRequest
2 голосов
/ 12 февраля 2012

В книге Внедрение зависимостей в .NET автор говорит, что Spring.NET не поддерживает создание пользовательских времен жизни объектов (см. Последний абзац раздела 12.2 [Управление временем жизни]).

Несмотря на то, что я новичок в этой платформе, я думаю, что это не так. Основываясь на моих исследованиях, я думаю, что можно определить пользовательские времена жизни, реализовав интерфейс ITargetSource, хотя, возможно, этот интерфейс может сделать намного больше (как некоторые предопределенные реализации включают в себя пул объектов и цели с горячей заменой и т. Д.).

Правильно ли мое понимание? Если да, каковы точные логические шаги для создания и настройки пользовательского времени жизни? Если нет, то как создать пользовательское время жизни объекта в Spring.NET?

1 Ответ

3 голосов
/ 19 февраля 2012

Хорошо, поэтому я фактически задал еще один вопрос здесь и, похоже, ответил на этот самый вопрос в процессе (это один из тех редких случаев, когда вы отвечаете на два своих вопроса одним ответом, опубликованным вами самим) ). Если вы ответите на этот другой вопрос, вы увидите, что действительно можно определить время жизни в Spring.NET.

Итак, подведем итог: пользовательское время жизни в Spring.NET может быть создано путем реализации интерфейса ITargetSource, хотя, возможно, это тонкий интерфейс, и его можно использовать для создания интересных вещей при создании целей. Доступно несколько реализаций, включая (но не ограничиваясь):

  • SingletonTargetSource (предоставляет время жизни синглтона)
  • PrototypeTargetSource (обеспечивает переходное время жизни)
  • ThreadLocalTargetSource (обеспечивает время жизни в области потока)
  • SimplePoolTargetSource (обеспечивает пул объектов)
  • HotSwappableTargetSource (предоставляет возможность менять цели во время выполнения)

Интересно, что применение времени жизни к вашим объектам может сильно отличаться в зависимости от того, какое время жизни вы хотите. Все объекты в Spring.NET по умолчанию являются одноэлементными. Чтобы указать объект как прототип (Spring.NET говорят о переходном процессе), вы устанавливаете singleton = "false" следующим образом:

<object id="..." type="..." singleton="false"/>

К сожалению, нет такого удобного свойства для оставшихся предоставленных времен жизни (включая ваши пользовательские реализации). Итак, допустим, вы хотите настроить объект с локальной областью потока. Вот как это можно сделать с помощью ProxyFactoryObject:

<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net">
    <object id="ConsoleLoggingBeforeAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor">
        <property name="Advice">
            <object type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
        </property>
    </object>

    <object id="ServiceCommandTargetSource" type="Spring.Aop.Target.ThreadLocalTargetSource">
        <property name="TargetObjectName" value="ServiceCommandTarget"/>
    </object>

    <object id="ServiceCommandTarget" type="Spring.Examples.AopQuickStart.ServiceCommand" singleton="false"/>

    <object name="ServiceCommand" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="TargetSource" ref="ServiceCommandTargetSource"/>
        <property name="InterceptorNames">
            <list>
                <value>ConsoleLoggingBeforeAdvisor</value>
            </list>
        </property>
    </object>
</objects>

Опять же, если вы хотите получить те же результаты, что и в приведенной выше конфигурации, но с использованием DefaultAdvisorAutoProxyCreator, вам придется сделать это совершенно другим способом, включая реализацию пользовательского типа, реализующего интерфейс ITargetSourceCreator.

Вот голая реализация ITargetSourceCreator, которая создает ThreadLocalTargetSourceCreator:

namespace Spring.Examples.AopQuickStart {
    public class ThreadLocalTargetSourceCreator : AbstractPrototypeTargetSourceCreator, ITargetSourceCreator {
        private readonly ThreadLocalTargetSource _threadLocalTargetSource;

        public ThreadLocalTargetSourceCreator() {
            _threadLocalTargetSource = new ThreadLocalTargetSource();
        }

        protected override AbstractPrototypeTargetSource CreatePrototypeTargetSource(Type objectType, string name, IObjectFactory factory) {
            return _threadLocalTargetSource;
        }
    }
}

Наконец, вам нужно использовать следующую конфигурацию, чтобы использовать вышеуказанный ITargetSourceCreator с DefaultAdvisorAutoProxyCreator для создания экземпляров целевого типа в локальной области потока:

<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net" default-autowire="constructor">
    <object id="ConsoleLoggingBeforeAdvice" type="Spring.Aop.Support.DefaultPointcutAdvisor">
        <property name="Advice">
            <object type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice" />
        </property>
    </object>

    <object id="ServiceCommand" type="Spring.Examples.AopQuickStart.ServiceCommand" singleton="false"/>

    <object type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator">
        <property name="CustomTargetSourceCreators">
            <list element-type="Spring.Aop.Framework.AutoProxy.ITargetSourceCreator">
                <object type="Spring.Examples.AopQuickStart.ThreadLocalTargetSourceCreator"/>
            </list>
        </property>
    </object>
</objects>

По моему мнению, способ настройки времени жизни, отличного от синглтона (по умолчанию) и прототипа, несколько не интуитивен и определенно не оптимизирован для различных типов реализаций прокси-фабрики (ProxyFactoryObject и DefaultAdvisorAutoProxyCreator)

В целом, да. Spring.NET поддерживает настраиваемое время жизни. Если ни одно из предопределенных времен жизни не соответствует вашим требованиям, вы можете создать собственный срок жизни, реализовав интерфейс ITargetSource и настроив его соответствующим образом.

...