Делает Spring.NET Поддержка Создания Пользовательских Сроков Службы Объектов?


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

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

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

1 2

1 ответ:

Хорошо, поэтому я на самом деле задал еще один вопрос здесь и, похоже, ответил на этот самый вопрос в процессе (это один из тех редких случаев, когда вы отвечаете на два ваших собственных вопроса с одним ответом, опубликованным вами). Если вы проследите за этим другим вопросом, вы увидите, что действительно можно определить обычное время жизни в 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 vs. DefaultAdvisorAutoProxyCreator)

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