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