Print
Lifecycle Compared

Lifecycle for prototype components

Spring lifecyle and Pico lifecycle both handle Singleton components only. There's just no lifecycle support for prototype components.

Yan and Nuts are different. In Yan, there's absolutely no need to distinguish between singleton and non-singleton components when talking about life cycle management.

It is perfectly legal to say:

<ctor id="nonsingleton" class="BankAccount" singleton="false" initializer="init" disposer="destroy"/>

No matter how many actual instances this component spits out, the "destroy" method is guaranteed to be called when cleaning up the system, as long as these instances are not garbage collected yet.

This makes things simpler and more consistent.

Complex lifecycle problem

Spring provides InitializingBean and DisposingBean for components who don't mind to be Spring-coupled to implement life cycle logic.

Pico presents Startable, Stoppable for the same purpose.

Plus, Spring provides a nice declarative lifecycle support using "init-method", "destroy-method" attributes. Although I'm not very clear what is the counterpart in Pico, I wouldn't doubt Pico's ability to support the same kind of declarative life cycle.

Nuts has a similar declarative life cycle support as Spring. "initializer", "starter", "stopper", "disposer" attributes can be used to define the 4 standard life cycles.

Yet, there may still be cases where these lifecycle supports are not capable of dealing with.

Let's look at a nasty example.

We have a class named "Engine". The Engine class is defined as:

public class Engine{
  public void shutdown(boolean force, int timeout){...}
  public void stop(){...}
}

The "stop" method is easy. But the "shutdown" method is trickier. The "force" parameter determines whether a force-shutdown is required; the "timeout" parameter specifies the maximal time to wait when "force" is false.

Such parametered life cycle method cannot be expressed by the simple "destroy-method" or "disposer".

To make it more complex, we assume there's a facade class EngineManager that's responsible for initializing and starting up an Engine object:

public class EngineManager{
  public static void initEngine(Engine engine){...}
  public static void startEngine(Engine engine){...}
}

"initEngine" and "startEngine" are not part of the Engine class, so the "init-method", "starter" approach don't fit either.

Yes, this design may not be completely ideal at all. It is just an example designed to make things harder. But hey, I mean, real life is seldom ideal. Occasionally either you or I will have to deal with sub-ideal library design or legacy code.

Nuts Solution

Spring has a MethodInvokingFactoryBean that is recommended by Spring reference manual to do some non-standard initialization.

The following words and code are copied from Spring reference manual:

it is sometimes necessary to call a static or non-static method in one class, just to perform some sort of initialization, before some other class is used. Additionally, it is sometimes necessary to set a property on a bean, as the result of a method call on another bean in the container, or a static method call on any arbitrary class.

<bean id="force-init" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="staticMethod"><value>com.example.MyClass.initialize</value></property>
</bean>

<bean id="bean1" class="..." depends-on="force-init">
  ...
</bean>

However, even for the "initialize" method, MethodInvokingFactoryBean is not a fit:

<bean id="init_engine" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="staticMethod"><value>com.example.EngineManager.initEngine</value></property>
  <property name="arguments">???</property>
</bean>

<bean id="engine" class="..." depends-on="init_engine">
  ...
</bean>

The "EngineManager.initEngine()" requires an Engine object as parameter, and there's no way for us to pass this object to MethodInvokingFactoryBean.

For the "shutdown" and "start", I was not able to find any solution from Spring's reference.

So, what does Nuts offer? Nuts has a rich and extensible set of tags for various different logic. The <lifecycle> tag is the key. Let's first look at the code:

<sequence id="engine">
  <bean var="result" class="com.example.MyEngine" args="..." stopper="stop"/>
  <lifecycle name="initializer">
    <method class="com.example.EngineManager" name="initEngine" args="$result"/>
  </lifecycle>
  <lifecycle name="starter">
    <method class="com.example.EngineManager" name="startEngine" args="$result"/>
  </lifecycle>
  <lifecycle name="disposer">
    <method component="$result" name="shutdown" args="false, 10"/>
  </lifecycle>
  <return val="$result"/>
</sequence>

Conceptually, the entire process of creating an Engine object is constituted with 3 steps:

  1. Create the Engine object.
  2. Declare these non-standard life cycle callbacks with the <lifecycle> tag.
  3. return the Engine object.

The "name" attribute of <lifecycle> is used to distinguish different life cycle phase.

A sub-component is then used to decribe the life cycle call back.

When the "engine" component is instantiated, the life cycle callbacks will be registered and invoked at the right time by the framework.

The xml code can also be written in Java using Yan API directly by repeatedly applying the "Component.bind()" method. But writing it in xml is far more clear and easier.


Created by benyu

On Mon Nov 28 16:40:18 CST 2005

Using TimTam

Powered by Atlassian Confluence