Spring 5 Functional Bean Registration
Last updated: May 4, 2023
1. Overview
Spring 5 comes with support for functional bean registration in the application context.
Simply put, this can be done through overloaded versions of a new registerBean() method defined in the GenericApplicationContext class.
Let’s have a look at a few examples of this functionality in action.
2. Maven Dependencies
The quickest way to setup a Spring 5 project is to use Spring Boot by adding the spring-boot-starter-parent dependency to the pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
</parent>
We also need the spring-boot-starter-web and spring-boot-starter-test for our example, to use a web application context in a JUnit test:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Of course, Spring Boot is not necessary in order to use the new functional way to register a bean. We could also just add the spring-core dependency directly:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.3</version>
</dependency>
3. Functional Bean Registration
The registerBean() API can receive two types of functional interfaces as parameters:
- a Supplier argument used to create the object
- a BeanDefinitionCustomizer vararg which can be used to provide one or more lambda expressions to customize the BeanDefinition; this interface has a single customize() method
First, let’s create a very simple class definition that we will use to create beans:
public class MyService {
public int getRandomNumber() {
return new Random().nextInt(10);
}
}
Let’s also add a @SpringBootApplication class that we can use to run a JUnit test:
@SpringBootApplication
public class Spring5Application {
public static void main(String[] args) {
SpringApplication.run(Spring5Application.class, args);
}
}
Next, we can set up our test class using the @SpringBootTest annotation to create a GenericWebApplicationContext instance:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Spring5Application.class)
public class BeanRegistrationIntegrationTest {
@Autowired
private GenericWebApplicationContext context;
//...
}
We’re using the GenericWebApplicationContext type in our example, but any type of application context can be used in the same way to register a bean.
Let’s see how we can register a bean using a lambda expression for creating the instance:
context.registerBean(MyService.class, () -> new MyService());
Let’s verify that we can now retrieve the bean and use it:
MyService myService = (MyService) context.getBean("com.baeldung.functional.MyService");
assertTrue(myService.getRandomNumber() < 10);
We can see in this example that if the bean name isn’t explicitly defined, it will be determined from the lower-case name of the class. The same method above can also be used with an explicit bean name:
context.registerBean("mySecondService", MyService.class, () -> new MyService());
Next, let’s see how we can register a bean by adding a lambda expression to customize it:
context.registerBean("myCallbackService", MyService.class,
() -> new MyService(), bd -> bd.setAutowireCandidate(false));
This argument is a callback that we can use to set bean properties such as autowire-candidate flag or primary flag.
4. Conclusion
In this quick tutorial, we’ve seen how we can use the functional way of registering a bean.
The source code for the example can be found over on GitHub.