A factory bean is a bean that serves as a factory for creating other beans within the IoC container. Conceptually, a factory bean is very similar to a factory method, but it is a Spring-specific bean that can be identified by the Spring IoC container during bean construction and can be used by container to instantiate other beans.
Creating beans using FactoryBean
To create a factory bean, all you have to do is to implement the FactoryBean
interface by your creator bean class which will be creating actual other beans. Or to keep it simple, you can extend AbstractFactoryBean
class.
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.
public class EmployeeFactoryBean extends AbstractFactoryBean<Object> { /This method will be called by container to create new instances @Override protected Object createInstance() throws Exception { //code } //This method is required for autowiring to work correctly @Override public Class<EmployeeDTO> getObjectType() { return EmployeeDTO.class; } }
Why use factory beans?
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
.
In most cases, you rarely have to write any custom factory beans, because they are framework-specific and cannot be used outside the scope of the Spring IoC container.
FactoryBean Demo
In this example, I am creating a factory bean to instantiate different types of Employee
objects e.g. their manager, director etc. with some pre-populated attributes.
Our EmployeeDTO
class looks like this.
package com.howtodoinjava.demo.model; public class EmployeeDTO { private Integer id; private String firstName; private String lastName; private String designation; //Setters and Getters are hidden behind this comment. @Override public String toString() { return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", type=" + designation + "]"; } }
EmployeeFactoryBean
class extends AbstractFactoryBean
class and implements it’s two methods createInstance()
and getObjectType()
.
import org.springframework.beans.factory.config.AbstractFactoryBean; import com.howtodoinjava.demo.model.EmployeeDTO; public class EmployeeFactoryBean extends AbstractFactoryBean<Object> { private String designation; public String getDesignation() { return designation; } public void setDesignation(String designation) { this.designation = designation; } //This method will be called by container to create new instances @Override protected Object createInstance() throws Exception { EmployeeDTO employee = new EmployeeDTO(); employee.setId(-1); employee.setFirstName("dummy"); employee.setLastName("dummy"); //Set designation here employee.setDesignation(designation); return employee; } //This method is required for autowiring to work correctly @Override public Class<EmployeeDTO> getObjectType() { return EmployeeDTO.class; } }
You will define various Employee
types in context file as below.
<bean id="manager" class="com.howtodoinjava.demo.factory.EmployeeFactoryBean"> <property name="designation" value="Manager" /> </bean> <bean id="director" class="com.howtodoinjava.demo.factory.EmployeeFactoryBean"> <property name="designation" value="Director" /> </bean>
To test above factory beans, use below code:
public class TestSpringContext { @SuppressWarnings("resource") public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); EmployeeDTO manager = (EmployeeDTO) context.getBean("manager"); System.out.println(manager); EmployeeDTO director = (EmployeeDTO) context.getBean("director"); System.out.println(director); } } Output: Employee [id=-1, firstName=dummy, lastName=dummy, type=Manager] Employee [id=-1, firstName=dummy, lastName=dummy, type=Director]
As you can see that EmployeeFactoryBean
created two different employee objects using same factory method.
Getting FactoryBean instance itself
If you want to get the instance of EmployeeFactoryBean
itself, then you can add an “&” before the bean name.
EmployeeFactoryBean factory = (EmployeeFactoryBean) context.getBean("&director"); System.out.println(factory.getDesignation()); System.out.println(factory.getObjectType()); System.out.println(factory.getObject()); Output: Director class com.howtodoinjava.demo.model.EmployeeDTO Employee [id=-1, firstName=dummy, lastName=dummy, type=Director]
Drop me your queries in comments section.
Happy Learning !!
Leave a Reply