Lazy bean instantiation in Spring 2.0
Spring 2.0 introduces a new way of instantiating beans defined in a
bean factory—lazily. Generally all singleton beans are
instantiated as one of the last things that a bean factory does. You
can now change this behaviour slightly and ensure that a bean factory
doesn’t instantiate your bean at all - until such time as it’s
requested for example.
How to do it
Simply use the new lazy-init attribute in your bean definition. For example:
<bean id="turtle" class="com.memestorm.FooT"
lazy-init=”true” />
<bean id=”fox” class=”com.memestorm.FooF”
lazy-init=”false” />
Here turtle is defined to instantiate lazily, while fox will do so eagerly. In fact, we don’t need the lazy-init="false" attribute on fox at all - by default things are not lazy.
What happens?
Well, if these beans were defined in your application context then the fox bean will be created as usual (eagerly, as a singleton), but the turtle won’t be. That’s almost all there is to it. Of course, if your Java code tries to grab the bean from the context it will be instantiated at that time:
FooF = (FooF) context.getBean("fox");
There is a caveat. If turtle was defined as dependency of fox, then of course the context will ensure that turtle is created eagerly too. It’s the only way to satisfy the constraint after all. So for example, here both beans will be created eagerly even though one is marked as lazy:
<bean id="not-quite-turtle" class="com.memestorm.FooT"
lazy-init=”true” />
<bean id=”fox” class=”com.memestorm.FooF”
depends-on=”turtle” />
A possible use
I found a possible use in the petclinic application distributed with Spring. Here it is in a nutshell. Say you have two beans, in this case implementing specialized functionality:
<bean id="hsqlClinic" class="org.springframework.....HsqlJdbcClinic"
lazy-init="true">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="mysqlClinic" class="org.springframework.....MySQLJdbcClinic"
lazy-init="true">
<property name="dataSource" ref="dataSource"/>
</bean>
Now say one of these classes will be used somewhere, say as the target of an transaction intercepter:
<bean id="clinic" class="org....TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="${petclinic.jdbcImplBeanName}"/>
</bean>
Now it should be clear to you. If, in my properties file, I set petclinic.jdbcImplBeanName=hsqlClinic, then the hsqlClinic bean will be used. Moreover, the mysqlClinic bean won’t even be instantiated. This nicely externalizes the configuration. To switch implementations, merely change the property to mysqlClinic.
How does it work?
You don’t have to know this, but here’s how the magic happens. The essential difference is in the preInstantiateSingletons() method in DefaultListableBeanFactory. This is the magic method that pre-instantiates all singletons defined in the bean factory. All that’s changed here, is that it ignores the bean if the lazy-init is set to true:
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
if (!cacheContainsSingleton(beanName) && containsBeanDefinition(beanName)) {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
….do instantiation work and put result in cache….
}
}
}
ioc lazy
Print This Post
on June 5th, 2006 at 10:41 am
Unless I am misunderstanding your post or you are mistaken. The lazy-init attribute has been available since at least Spring 1.1… perhaps earlier. You can also specify the entire bean context file to default to laziness by setting the default-lazy-init attribute of the beans element to true.
I have not poked around into the source to ensure that its working 100% correctly, but we use and have seen the lazy behavior working in our application.
Maybe some bugs have been fixed or maybe it’s now a little lazier?
on June 5th, 2006 at 11:13 am
Hey Chris,
I just checked in the 1.2 documentation, and it is indeed there-hidden away.
I didn’t know about it until recently…Thanks for the heads up.
Jon
on June 5th, 2006 at 4:52 pm
lazy-init has actually been in there for a long, long time…
The default behavior in Spring has always been to eagerly instantiate singletons, and lazily instantiate prototype (non-singleton) beans.
However, it’s been possible to turn on lazy init for singletons as well, since well before Spring 1.0, by using the lazy-init attribute. Looking back in the logs, this capability appeared on Nov. 5, 2003.
Colin
on June 5th, 2006 at 9:46 pm
Hi Colin,
As noted in my earlier comment, I acknowledge this fact. I thought it was new….Still, I find it a nice little feature…
Regards, Jon
on June 6th, 2006 at 1:43 pm
Nevertheless it’s a good pointer to those who might have missed it or couldn’t identify a usecase for it. Keep up the good work.
Thanks
Twice.
on August 8th, 2006 at 7:02 am
One really handy use of lazy-init I’ve found is to specify my JNDI data source bean as lazy, so that when I’m testing things using another internal (C3P0) data source, the JNDI one is never actually instantiated, which means the app’s initialization doesn’t bomb out. This makes it really easy to transparently switch between configurations using only properties files.
on November 20th, 2006 at 9:33 am
Hi,
how can i discover the status of a “lazy” bean?
I mean, how can i know if the bean is active or not?
Thanks,
Matteo
on September 11th, 2007 at 10:01 am
A little bit late
but i wrote a blog on this: http://janhoeve.blogspot.com/2007/08/speedup-development-by-making-spring.html
I present a way to make all spring beans lazy at development time.
This way you can speed up the code/build/deploy/test cycle.