In this article, I will show you how to use FactoryBean to create or return an existing instance of an Object. The FactoryBean interface has three methods.
There ate two types of factory methods:
First let me show you the FactoryBean class
My Bar class and Foo class are pretty simple. For simplicity case, I haven't added any implementation.
My first example is about static factory method. Here is the context xml.
Even though bean "barFactory" is for class BarFactoryBean, beanFactory.getObject() will always return the object the FactoryBean is managing.
If there is ever a need to retrieve the actual FactoryBean and not the object the factory creates, it be retrieved using "&beanId".
In our example, beanFactory.getBean("&barFactory") will return BarFactory rather than Bar whereas beanFactory.getBean("barFactory") will return Bar.
In the below test case, you can see beanFactory.getBean("barFactory") returns us Bar and NOT BarFactory. In the test case, we verify the types.
My second example is about the instance factory method. We will now modify the Bar class and introduce Foo createFoo() method.
Instance factory method is invoked on the instance returned by the FactoryBean bean.
We will modify our context file to define factory-bean and factory-method attributes:
In the below test case, you can see beanFactory.getBean("fooFactory") returns us Foo. In its bean configuration, note the factory-bean and factory-method attributes. The factory-bean returns us an instance of FactoryBean's object which is Bar in our case. Next, it invokes the factory-method, createFoo in our case.
We can also define a bean that returns us the FactoryBean itself.
To demonstrate this, I introduce a new class BarFactoryHolder which holds BarFactoryBean. In the context file, we will set the property barFactoryBean to the FactoryBean instance returned by "&barFactoryBean":
We will now define BarFactoryHolder bean in our context file:
Note barFactoryBean property is set to value referred by bean id "&barFactory".
FactoryBean methods
- getObject() method returns an instance created by the factory.
- getObjectType() method returns the type of instance that will be returned by getObject().
- isSingleton() method returns true if you want the Object created to be cached by the bean factory
Why do we need to use a FactoryBean?
We may need this when the constructor of the class is private and is managed by a factory.
Types of factory methods:
There ate two types of factory methods:- static factory method
- instance factory method
First let me show you the FactoryBean class
package springdemo; import org.springframework.beans.factory.FactoryBean; public class BarFactoryBean implements FactoryBean{ @Override public Bar getObject() throws Exception { return new Bar(); } @Override public Class getObjectType() { return Bar.class; } @Override public boolean isSingleton() { return true; } }
My Bar class and Foo class are pretty simple. For simplicity case, I haven't added any implementation.
public class Foo { }
public class Bar { }
My first example is about static factory method. Here is the context xml.
<beans default-lazy-init="true">
<bean name="barFactory" class="springdemo.BarFactoryBean"/>
</beans>
Even though bean "barFactory" is for class BarFactoryBean, beanFactory.getObject() will always return the object the FactoryBean is managing.
If there is ever a need to retrieve the actual FactoryBean and not the object the factory creates, it be retrieved using "&beanId".
In our example, beanFactory.getBean("&barFactory") will return BarFactory rather than Bar whereas beanFactory.getBean("barFactory") will return Bar.
In the below test case, you can see beanFactory.getBean("barFactory") returns us Bar and NOT BarFactory. In the test case, we verify the types.
@Test public void testStaticFactory() { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(factory).loadBeanDefinitions("/springdemo/testFactoryBeanContext.xml"); Object bar = factory.getBean("barFactory"); assertTrue(bar instanceof Bar); assertTrue(factory.getBean("&barFactory") instanceof BarFactoryBean); }
My second example is about the instance factory method. We will now modify the Bar class and introduce Foo createFoo() method.
package springdemo; public class Bar { public Foo createFoo() { return new Foo(); } }
Instance factory method is invoked on the instance returned by the FactoryBean bean.
We will modify our context file to define factory-bean and factory-method attributes:
<beans default-lazy-init="true">
<bean name="barFactory" class="springdemo.BarFactoryBean"/>
<bean id="fooFactory" factory-bean="barFactory" factory-method="createFoo"/>
</beans>
In the below test case, you can see beanFactory.getBean("fooFactory") returns us Foo. In its bean configuration, note the factory-bean and factory-method attributes. The factory-bean returns us an instance of FactoryBean's object which is Bar in our case. Next, it invokes the factory-method, createFoo in our case.
@Test public void testFactoryInstanceMethod() { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(factory).loadBeanDefinitions("/springdemo/testFactoryBeanContext.xml"); Object foo = factory.getBean("fooFactory"); }
We can also define a bean that returns us the FactoryBean itself.
To demonstrate this, I introduce a new class BarFactoryHolder which holds BarFactoryBean. In the context file, we will set the property barFactoryBean to the FactoryBean instance returned by "&barFactoryBean":
package springdemo; public class BarFactoryHolder { private BarFactoryBean barFactoryBean; public void setBarFactoryBean(BarFactoryBean barFactoryBean) { this.barFactoryBean = barFactoryBean; } public BarFactoryBean getBarFactoryBean() { return barFactoryBean; } }
We will now define BarFactoryHolder bean in our context file:
<bean id="barFactoryHolder" class="springdemo.BarFactoryHolder">
<property name="barFactoryBean" ref="&barFactory"/>
</bean>
In the test case, I first get the barFactoryHolder bean and then call the getBarFactoryBean to access the factory bean.Note barFactoryBean property is set to value referred by bean id "&barFactory".
@Test public void testFactoryBean() { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(factory).loadBeanDefinitions("/springdemo/testFactoryBeanContext.xml"); BarFactoryHolder barFactoryHolder = (BarFactoryHolder) factory.getBean("barFactoryHolder"); assertTrue(barFactoryHolder.getBarFactoryBean() instanceof BarFactoryBean); }
No comments:
Post a Comment