In the book Dependency Injection in .NET, the author says that Spring.NET doesn't support creation of custom object lifetimes (See last paragraph of section 12.2 [Managing lifetime]).

Even though I am new to the framework, I think this may not be the case. Based on my research so far, I think one can define custom lifetimes by implementing the ITargetSource interface, though, arguably, this interface can do much more than that (like some predefined implementations include object pooling and hot-swappable targets etc.).

Is my understanding correct? If yes, what are the exact logical steps for creating AND configuring a custom lifetime? If no, how does one create a custom object lifetime in Spring.NET?

有帮助吗?

解决方案

Ok, so I actually asked another question here and seems like answered this very question in the process (this is one of those rare occasions where you answer two of your own questions with one answer posted by yourself). If you follow that other question, you'll see that it's indeed possible to define custom life times in Spring.NET.

So in summary, a custom lifetime in Spring.NET can be created by implementing the ITargetSource interface, though, arguably, it's a subtle interface and can be used to do fancy things around creating targets. There are already few implementations available including (but not limited to):

  • SingletonTargetSource (provides the singleton lifetime)
  • PrototypeTargetSource (provides the transient lifetime)
  • ThreadLocalTargetSource (provides thread-scoped lifetime)
  • SimplePoolTargetSource (provides object pooling)
  • HotSwappableTargetSource (provides the capability to swap targets at runtime)

Interestingly, applying a lifetime to your objects can be very different depending on what lifetime you want. All objects in Spring.NET are singleton by default. To specify an object as prototype (Spring.NET speak for transient), you set singleton="false" as follows:

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

Unfortunately, there's no such convenient property for the rest of the provided lifetimes (including your custom implementations). So, let's say you want to configure an object with thread-local scope. Here's how you'd do that using 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>

Again, if you want to achieve the exact same results as the above configuration but using DefaultAdvisorAutoProxyCreator, you'll have to do it in an entirely different way, including implementing a custom type that implements the ITargetSourceCreator interface.

Here's a bare bone ITargetSourceCreator implementation that creates a 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;
        }
    }
}

Finally, you need to use the following configuration to use the above ITargetSourceCreator with DefaultAdvisorAutoProxyCreator to create instances of your target type at thread-local scope:

<?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>

In my opinion, the way you configure lifetimes other than singleton (default) and prototype is somewhat non-intuitive and definitely not streamlined across different types of proxy factory implementations (ProxyFactoryObject vs. DefaultAdvisorAutoProxyCreator)

In summary, yes, Spring.NET does support custom lifetimes. If none of the predefined lifetimes meet your requirements, you can create a custom lifetime by implementing the ITargetSource interface and configuring it appropriately.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top