Creating Beans Using Spring’s Factory Bean

The basic requirement of a factory bean is to implement the FactoryBean interface. For your convenience, Spring provides an abstract template class, AbstractFactoryBean, for you to extend. Factory beans are mostly used to implement framework facilities. Here are some examples:

• When looking up an object (such as a data source) from JNDI, you can use JndiObjectFactoryBean.

• When using classic Spring AOP to create a proxy for a bean, you can use ProxyFactoryBean.

• When creating a Hibernate session factory in the IoC container, you can use LocalSessionFactoryBean.

However, as a framework user, you seldom have to write custom factory beans, because they are framework-specific and cannot be used outside the scope of the Spring IoC container. Actually, you are always able to implement an equivalent factory method for a factory bean.

How It Works

Although you’ll seldom have to write custom factory beans, you may better understand their internal mechanisms through an example. For example, you can write a factory bean for creating a product with a discount applied to the price. It accepts a product property and a discount property to apply the discount to the product and return it as a new bean.

package com.shop;
import org.springframework.beans.factory.config.AbstractFactoryBean;
public class DiscountFactoryBean extends AbstractFactoryBean {
private Product product;
private double discount;
public void setProduct(Product product) {
this.product = product;
}
public void setDiscount(double discount) {
this.discount = discount;
}
public Class getObjectType() {
return product.getClass();
}
protected Object createInstance() throws Exception {
product.setPrice(product.getPrice() * (1 – discount));
return product;
}
}

By extending the AbstractFactoryBean class, your factory bean can simply override the createInstance() method to create the target bean instance. In addition, you have to return the target bean’s type in the getObjectType() method for the auto-wiring feature to work properly.

Next, you can declare your product instances with DiscountFactoryBean. Each time you request a bean that implements the FactoryBean interface, the Spring IoC container will use this factory bean to create the target bean and return it to you. If you are sure that you want to get the factory bean instance itself, you can use the bean name preceded by &.

<beans …>
<bean id="aaa"
class="com.shop.DiscountFactoryBean">
<property name="product">
<bean class="com.shop.Battery">
<constructor-arg value="AAA" />
<constructor-arg value="2.5" />
</bean>
</property>
<property name="discount" value="0.2" />
</bean>
<bean id="cdrw"
class="com.shop.DiscountFactoryBean">
<property name="product">
<bean class="com.shop.Disc">
<constructor-arg value="CD-RW" />
<constructor-arg value="1.5" />
</bean>
</property>
<property name="discount" value="0.1" />
</bean>
</beans>

The preceding factory bean configuration works in a similar way to the following code snippet:

DiscountFactoryBean &aaa = new DiscountFactoryBean();
&aaa.setProduct(new Battery("AAA", 2.5));
&aaa.setDiscount(0.2);
Product aaa = (Product) &aaa.createInstance();
DiscountFactoryBean &cdrw = new DiscountFactoryBean();
&cdrw.setProduct(new Disc("CD-RW", 1.5));
&cdrw.setDiscount(0.1);
Product cdrw = (Product) &cdrw.createInstance();