Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

Pico, Spring and Nuts all provide declarative singleton support.

Pico provides a CachingComponentAdapter for decorating a ComponentAdapter as a singleton; Yan has a singleton() method that internally creates a singleton decorator. Basically Pico and Yan share the same idea on how singleton is implemented.

Spring is slightly different. Singleton semantics is implemented centrally by the BeanFactory, rather than individual beans.

This approach taken by Spring lacks some flexibility compared to Pico/Yan's approach.

Pico and Yan also support scoped singleton, where cached instance is not simply stored in a member variable. For example, Yan allows the instance to be stored in a thread local object, which enables one instance per thread.

Let's see a more concrete example:

  • Component A is singleton.
  • Component B is prototype.
  • Component A has a property "b" whose type is B.
  • Every time component A is requested, the same instance is returned, but the property "b" should be given a fresh new instance of B.

The Java pseudo code is:

Code Block
private A singleton;
private A getSingletonInstance(){
  if(singleton==null){
    this.singleton = new A();
  }
  return singleton;
}
public synchronized A getInstance(){
  final A instance = getSingletonInstance();
  instance.setB(new B());
}

Bizarre requirement, you may say. Well, the following statements are copied from Spring reference:

There is however a problem when the bean lifecycles are different. Consider a singleton bean A which needs to use a non-singleton (prototype) bean B, perhaps on each method invocation on A. The container will only create the singleton bean A once, and thus only get the opportunity to set its properties once. There is no opportunity for the container to provide bean A with a new instance of bean B every time one is needed.

One solution to this problem is to forgo some inversion of control. Bean A can be aware of the container (as described here) by implementing BeanFactoryAware, and use programmatic means (as described here) to ask the container via a getBean("B") call for (a new) bean B every time it needs it. This is generally not a desirable solution since the bean code is then aware of and coupled to Spring.

Method Injection, an advanced feature of the BeanFactory, allows this use case to be handled in a clean fashion, along with some other scenarios.

3.3.4.1. Lookup method Injection
Lookup method injection refers to the ability of the container to override abstract or concrete methods on managed beans in the container, to return the result of looking up another named bean in the container. The lookup will typically be of a non-singleton bean as per the scenario described above (although it can also be a singleton). Spring implements this through a dynamically generated subclass overriding the method, using bytecode generation via the CGLIB library.

Honestly, I like neither of the solutions. Forgoing IOC isn't good and relying on bytecode generation sounds like a big deal to me.

As we just saw, this logic can be easily expressed in Java, why does it have to be so awkward in an IOC container?

I'll not show the Java code using Pico or Yan. It's not so fair to compare xml with a full blown programming language like Java after all.

In Nuts, this is what we will do to implement this requirement:

Code Block
<ctor id="getSingletonInstance" class="A" args="" singleton="true"/>
<bean id="getInstance" component="$getSingletonInstance"
    singleton="false" synchronized="true">
  <prop key="b">
    <ctor class="B" args=""/>
  </prop>
</bean>

We keep "getSingletonInstance" as singleton so that we will always get the same instance.
The "getInstance" is not singleton, so that the property "b" can be assigned with a fresh new instance of B every time "getInstance" is requested.

Slightly refactored, we can hide the "getSingletonInstance" as a nested sub-element:

Code Block
<bean id="getInstance" component="$getSingletonInstance"
    singleton="false" synchronized="true">
  <ctor id="getSingletonInstance" class="A" args="" singleton="true"/>
  <prop key="b">
    <ctor class="B" args=""/>
  </prop>
</bean>

Either way, it is a straight-forward translation of the Java pseudo code.