In Spring framework beans are by default singleton in scope with in the Spring container. Now if you have a Singleton Java class, or a factory class with a static method and you want to use that class with in the Spring framework to ensure that only one instance is created which is a singleton within the scope of JVM not only with in the scope of Spring container. For such scenario you need to use the factory-method attribute of the bean element in the Spring framework.
factory-method and factory-bean attribute in Spring
There may be a case when in a factory class the method which creates an instance of the class is not static,
in that case you need to use factory-bean
attribute along with factory-method
attribute.
So we have two scenarios here-
- Static factory method- Use factory-method attribute, specify the factory method that has to be used with the factory-method attribute.
- Non-static (instance) factory method- Use factory-bean attribute to specify the bean where factory method resides, use factory-method to specify the method.
Let us see an example of factory-method in Spring to have better understanding.
Spring factory-method with Singleton class Example
Let's create a singleton class which lazily loads the class instance and configure it in Spring using factory-method
attribute.
Singleton class
package spring_core; public class Admin { // private constructor private Admin(){ } private static class AdminHolder(){ private static final Admin INSTANCE = new Admin(); } public static Admin getInstance(){ return AdminHolder.INSTANCE; } }
XML Configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="adminBean" class="org.netjs.prog.Admin" factory-method="getInstance"/> </beans>
You can use the following Java program to run it-
import org.netjs.prog.Admin; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); Admin bean = (Admin) context.getBean("adminBean"); System.out.println("Values " + bean); context.close(); } }
Output
creating instance of class Admin Values org.netjs.prog.Admin@343f4d3d
Just to make it clearer that factory-method will help you in creating just a single instance let us have one more example. You must be knowing that Spring uses reflection to instantiate objects and it will invoke constructor regardless of constructor's visibility. Even if there is a private constructor Spring will create an instance of the class. Now you must be wondering then what does factory method do?
If we have the same class as above and in XML configuration we define 4 beans of the same class 2 using Spring factory-method attribute and 2 beans without it.
XML Configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="adminBean" class="org.netjs.prog.Admin" /> <bean id="adminBean1" class="org.netjs.prog.Admin" /> <bean id="adminBean2" class="org.netjs.prog.Admin" factory-method="getInstance"/> <bean id="adminBean3" class="org.netjs.prog.Admin" factory-method="getInstance"/> </beans>
Java Class
import org.netjs.prog.Admin; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); Admin bean = (Admin) context.getBean("adminBean"); System.out.println("Values " + bean); Admin bean1 = (Admin) context.getBean("adminBean1"); System.out.println("Values " + bean1); Admin bean2 = (Admin) context.getBean("adminBean2"); System.out.println("Values " + bean2); Admin bean3 = (Admin) context.getBean("adminBean3"); System.out.println("Values " + bean3); context.close(); } }
Output
creating instance of class Admin creating instance of class Admin Values org.netjs.prog.Admin@343f4d3d Values org.netjs.prog.Admin@53b32d7 Values org.netjs.prog.Admin@5442a311 Values org.netjs.prog.Admin@5442a311
If you have noticed first two bean objects are different even if it is a Singleton class and notice the other two objects which are created using factory-method attribute they are same! That's why you need to use factory-method attribute if you want to ensure that your object is singleton.
Spring factory-method with static method Example
As mentioned it's not only with singleton class but also factory with static method where factory-method attribute can be used.
In this example we have a class with 2 fields and a factory class that create instance of the class. You can also pass argument to the factory method.
Test Bean class
public class TestBean { private int num; private String name; public int getNum() { return num; } public void setNum(int num) { this.num = num; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
TestBean Factory class
public class TestBeanFactory { public static TestBean createTestBean(int num){ TestBean testBean = new TestBean(); testBean.setNum(num); return testBean; } }
XML Configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="testBean" class="org.netjs.prog.TestBeanFactory" factory-method="createTestBean"> <constructor-arg value = "10" /> <property name="name" value = "test" /> </bean> </beans>
You can run this program using the following Java class-
import org.netjs.prog.TestBean; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); TestBean testBean = (TestBean) context.getBean("testBean"); System.out.println("Values " + testBean); System.out.println("Name - " + testBean.getName()); } }
Spring factory-method with non-static method Example
If you have instance factory method (non-static factory method) then you can't just use the factory-method attribute as it works with
the static method.
As example if I remove the static keyword from the method in the factory class used above-
public class TestBeanFactory { public TestBean createTestBean(int num){ TestBean testBean = new TestBean(); testBean.setNum(num); return testBean; } }
And then try to run it, it will give the following error-
Error creating bean with name 'testBean' defined in class path resource [appcontext.xml]: No matching factory method found: factory method 'createTestBean(String)'. Check that a method with the specified name and arguments exists and that it is static.
In this case, when you have a non-static factory method, you need to use factory-bean
attribute along with factory-method
attribute.
XML Configuration
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="testBeanFactory" class="org.netjs.prog.TestBeanFactory"/> <bean id="testBean" class="org.netjs.prog.TestBean" factory-bean="testBeanFactory" factory-method="createTestBean"> <constructor-arg value = "10" /> <property name="name" value = "test" /> </bean> </beans>
Now there is definition for Factory class also in the configuration and both factory-bean and factory-method attribute are used.
That's all for this topic Dependency Injection Using factory-method in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-