|
|||||
|
|||||
Lifecycle Compared
Lifecycle for prototype componentsSpring 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 problemSpring 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. 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 SolutionSpring has a MethodInvokingFactoryBean that is recommended by Spring reference manual to do some non-standard initialization.
<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:
The "name" attribute of <lifecycle> is used to distinguish different life cycle phase. 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 |
|||||
|
Copyright 2003-2006 - The Codehaus. All rights reserved unless otherwise noted.
Powered by Atlassian Confluence
|
|||||