Spring FactoryBean

0
In this article, I will show you an example of FactoryBean. It is used to create or return an existing instance of an Object. The FactoryBean interface has three methods.

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 are two types of factory methods:

  • static factory method
  • instance factory method

I will show you an example for each case.

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 bean ID "&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);
    }
Share.

Leave A Reply