Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

NPI – Spring Top – Temp – Non-Geo (Lightrun)

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
NPI – Lightrun – Spring (partner)

We rely on other people’s code in our own work. Every day. It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.

The problem is, of course, when things fall apart in production - debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky. It’s difficult to understand what talks to what and, specifically, which part of the underlying library is at fault.

Lightrun is a new kind of debugger.

It's one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics. No hotfixes, redeployments, or restarts required.

Learn more in this quick, 5-minute Lightrun tutorial:

>> The Essential List of Spring Boot Annotations and Their Use Cases

1. Introduction

Factory methods can be a useful technique for hiding complex creation logic within a single method call.

While we commonly create beans in Spring using constructor or field injection, we can also create Spring beans using factory methods.

In this tutorial, we will delve into creating Spring beans using both instance and static factory methods.

2. Instance Factory Method

A standard implementation of the factory method pattern is to create an instance method that returns the desired bean.

Additionally, we can configure Spring to create our desired bean with or without arguments.

2.1. Without Arguments

We can create a Foo class that represents our bean being created:

public class Foo {}

Then, we create an InstanceFooFactory class that includes a factory method, createInstance, that creates our Foo bean:

public class InstanceFooFactory {

    public Foo createInstance() {
        return new Foo();
    }
}

After that, we configure Spring:

  1. Create a bean for our factory class (InstanceFooFactory)
  2. Use the factory-bean attribute to reference our factory bean
  3. Use the factory-method attribute to reference our factory method (createInstance)

Applying this to a Spring XML configuration, we end up with:

<beans ...>

    <bean id="instanceFooFactory"
      class="com.baeldung.factorymethod.InstanceFooFactory" />

    <bean id="foo"
      factory-bean="instanceFooFactory"
      factory-method="createInstance" />

</beans>

Lastly, we autowire our desired Foo bean. Spring will then create our bean using our createInstance factory method:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/instance-config.xml")
public class InstanceFooFactoryIntegrationTest {

    @Autowired
    private Foo foo;
    
    @Test
    public void givenValidInstanceFactoryConfig_whenCreateFooInstance_thenInstanceIsNotNull() {
        assertNotNull(foo);
    }
}

2.2. With Arguments

We can also provide arguments to our instance factory method using the constructor-arg element in our Spring configuration.

First, we create a class, Bar, that utilizes an argument:

public class Bar {

    private String name;

    public Bar(String name) {
        this.name = name;
    }

    // ...getters & setters
}

Next, we create an instance factory class, InstanceBarFactory, with a factory method that accepts an argument and returns a Bar bean:

public class InstanceBarFactory {

    public Bar createInstance(String name) {
        return new Bar(name);
    }
}

Lastly, we add a constructor-arg element to our Bar bean definition:

<beans ...>

    <bean id="instanceBarFactory"
      class="com.baeldung.factorymethod.InstanceBarFactory" />

    <bean id="bar"
      factory-bean="instanceBarFactory"
      factory-method="createInstance">
        <constructor-arg value="someName" />
    </bean>

</beans>

We can then autowire our Bar bean in the same manner as we did for our Foo bean:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/instance-bar-config.xml")
public class InstanceBarFactoryIntegrationTest {

    @Autowired
    private Bar instance;
    
    @Test
    public void givenValidInstanceFactoryConfig_whenCreateInstance_thenNameIsCorrect() {
        assertNotNull(instance);
        assertEquals("someName", instance.getName());
    }
}

3. Static Factory Method

We can also configure Spring to use a static method as a factory method.

While instance factory methods should be preferred, this technique can be useful if we have existing, legacy static methods that produce desired beans. For example, if a factory method returns a singleton, we can configure Spring to use this singleton factory method.

Similar to instance factory methods, we can configure static methods with and without arguments.

3.1. Without Arguments

Using our Foo class as our desired bean, we can create a class, SingletonFooFactory, that includes a createInstance factory method that returns a singleton instance of Foo:

public class SingletonFooFactory {

    private static final Foo INSTANCE = new Foo();
    
    public static Foo createInstance() {
        return INSTANCE;
    }
}

This time, we only need to create one bean. This bean requires only two attributes:

  1. class – declares our factory class (SingletonFooFactory)
  2. factory-method – declares the static factory method (createInstance)

Applying this to our Spring XML configuration, we get:

<beans ...>

    <bean id="foo"
      class="com.baeldung.factorymethod.SingletonFooFactory"
      factory-method="createInstance" />

</beans>

Lastly, we autowire our Foo bean using the same structure as before:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/static-foo-config.xml")
public class SingletonFooFactoryIntegrationTest {

    @Autowired
    private Foo singleton;
    
    @Test
    public void givenValidStaticFactoryConfig_whenCreateInstance_thenInstanceIsNotNull() {
        assertNotNull(singleton);
    }
}

3.2. With Arguments

While we should avoid changing the state of static objects — like our singleton — when possible, we can still pass arguments to our static factory method.

To do this, we create a new factory method that accepts our desired arguments:

public class SingletonBarFactory {

    private static final Bar INSTANCE = new Bar("unnamed");
    
    public static Bar createInstance(String name) {
        INSTANCE.setName(name);
        return INSTANCE;
    }
}

After that, we configure Spring to pass in the desired argument using the constructor-arg element:

<beans ...>

    <bean id="bar"
      class="com.baeldung.factorymethod.SingletonBarFactory"
      factory-method="createInstance">
        <constructor-arg value="someName" />
    </bean>

</beans>

Lastly, we autowire our Bar bean using the same structure as before:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/static-bar-config.xml")
public class SingletonBarFactoryIntegrationTest {

    @Autowired
    private Bar instance;
    
    @Test
    public void givenValidStaticFactoryConfig_whenCreateInstance_thenNameIsCorrect() {
        assertNotNull(instance);
        assertEquals("someName", instance.getName());
    }
}

4. Conclusion

In this article, we looked at how to configure Spring to use instance and static factory methods — both with and without arguments.

While creating beans through constructor and field injection is more common, factory methods can be handy for complex creation steps and legacy code.

The code used in this article can be found over on GitHub.

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Generic footer banner
4 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are closed on this article!