@Configuration Spring Boot Tutorial

659 views

In this article, we’ll go through what @Configuration in Spring Boot is and how to use it.

1. What is @Configuration Annotation in Spring Boot

We use @Configuration in Spring Boot mainly to declare new beans that will be included in the Spring Context. We can inject these beans through @Autowired Annotation wherever we need them. Furthermore, @Configuration tags this class as a bean in order to be included in the Spring Context.

@Configuration has 3 attributes:

  • value, which allows you to specify the bean name.
  • proxyBeanMethods, which defaults to true.
  • Lastly, enforceUniqueMethods, which defaults to true.

We will see later in the examples how and why you might need to change them.

2. Setting Up The Project

First of all, you need to have Java installed, if you do not you can go through these tutorials depending on the OS your machine runs:

For this tutorial, we are using the IntelliJ IDEA Community edition which you can download here.

If you are not using this IDE, you also need to download Maven here.

The next step is to visit Spring initializr and generate a project according to these settings shown in the image:

Figure 1 – Spring Initializr

After having chosen the above options, press the GENERATE button, and a new spring boot project will be downloaded for you. Then you have to unzip the compressed archive and open the folder with your favorite IDE.

3. Creating the Services

In order to demonstrate how @Configuration works we will create 3 services:

  • PunctuationService, a service that provides punctuation marks such as “.” or “?”.
  • LowerCaseWordsService, a service that provides some lower-case words and has PunctuationService as a dependency.
  • Lastly, UpperCaseWordsService, a service that provides some upper-case words and has PunctuationService as a dependency.

PunctuationService:

package com.codelearnhub.configurationAnnotation.service;

import java.util.Arrays;
import java.util.List;

public class PunctuationService {

    private final List<Character> punctuationMarks = Arrays.asList('.', ';', '!', '?');

    public List<Character> getAllPunctuationMarks(){
        return punctuationMarks;
    }

}

LowerCaseWordsService:

package com.codelearnhub.configurationAnnotation.service;

import java.util.Arrays;
import java.util.List;

public class LowerCaseWordsService {

    private final PunctuationService punctuationService;
    private final List<String> words = Arrays.asList("code", "learn", "hub");

    public LowerCaseWordsService(PunctuationService punctuationService) {
        this.punctuationService = punctuationService;
    }

    public PunctuationService getPunctuationService() {
        return punctuationService;
    }

    public List<String> getAllWords(){
        return words;
    }
}

UpperCaseWordsService:

package com.codelearnhub.configurationAnnotation.service;

import java.util.Arrays;
import java.util.List;

public class UpperCaseWordsService {

    private final List<String> words = Arrays.asList("CODE", "LEARN", "HUB");
    private final PunctuationService punctuationService;

    public UpperCaseWordsService(PunctuationService punctuationService) {
        this.punctuationService = punctuationService;
    }

    public PunctuationService getPunctuationService() {
        return punctuationService;
    }

    public List<String> getAllWords(){
        return words;
    }
}

As you can observe we haven’t added any of the classes to the Spring Context since they do not have any annotation such as @Service.

4. Creating the Config Class Using @Configuration Annotation

Now it’s time to create the Configuration class and see how we can declare beans through it. Before we begin, let’s explain how the two aforementioned attributes behave.

4.1 proxyBeanMethods Attribute

This attribute specifies if @Bean annotated methods will use a proxy(more specifically CGLib). Note that setting this attribute to false(also known as @Bean Lite Mode) makes @Configuration annotation redundant and just @Component annotation would suffice.

The advantage of using a proxy is that whenever we call a @Bean annotated method, the same bean will be returned. However, this comes with some disadvantages:

  • Startup time might be slower in comparison to setting this attribute as false. Especially when a lot of @Configuration annotated classes exist.
  • You cannot declare both the class and any method as final as they need to be subclassed.

4.2 enforceUniqueMethods Attribute

This attribute is exactly what its name indicates; we cannot have two methods of the same.

As a result, overloading cannot be applied to every @Bean annotated method.

4.3 Using Defaults

The first case is when we do not change the values of proxyBeanMethods and enforceUniqueMethods.

package com.codelearnhub.configurationAnnotation.configuration;

import com.codelearnhub.configurationAnnotation.service.LowerCaseWordsService;
import com.codelearnhub.configurationAnnotation.service.PunctuationService;
import com.codelearnhub.configurationAnnotation.service.UpperCaseWordsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    @Bean
    public LowerCaseWordsService lowerCase(){
        return new LowerCaseWordsService(punctuationService());
    }

    @Bean
    public UpperCaseWordsService upperCase(){
        return new UpperCaseWordsService(punctuationService());
    }

    @Bean
    public PunctuationService punctuationService(){
        return new PunctuationService();
    }
}

The name of the bean by default matches the name of @Bean annotated method.

Three beans will be created (and the first two beans will use the third) upon startup since we used the @Bean annotation, even though we didn’t tag the respective classes with an annotation like @Component or @Service.

The next step is to test if only one PunctuationService bean was created; head to ConfigurationAnnotationApplication.java

package com.codelearnhub.configurationAnnotation;

import com.codelearnhub.configurationAnnotation.service.LowerCaseWordsService;
import com.codelearnhub.configurationAnnotation.service.UpperCaseWordsService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConfigurationAnnotationApplication {

	public static void main(String[] args) {
		var context = SpringApplication.run(ConfigurationAnnotationApplication.class, args);
		var lowerCaseBean = (LowerCaseWordsService) context.getBean("lowerCase");
		var upperCaseBean = (UpperCaseWordsService) context.getBean("upperCase");
		System.out.printf("Do both punctuation services point to the same object? %b",
				lowerCaseBean.getPunctuationService() == upperCaseBean.getPunctuationService()
		);
	}

}

Let’s explain what we did here:

  • We hold the context in a variable context.
  • Then we retrieve the lowerCase bean and UpperCase bean from the application context.
  • Then we check if the 2 beans have the same reference.

If you do run the app, you will see that true will be printed, as we have proxyBeanMethods set to true.

4.4 Using proxyBeanMethods as false

Now the only thing that we’ll change is the annotation to

@Configuration(proxyBeanMethods = false)

Now re-run the app and you will see that false is printed. This means that the second time punctuationService() method was called, a new bean was created.

4.5 Using enforceUniqueMethods as false:

Now set the @Configuration annotation to

@Configuration(enforceUniqueMethods = false)

and then add another method:

@Bean
public UpperCaseWordsService upperCase(String dummy){
    return new UpperCaseWordsService(punctuationService());
}

If you run the app, no exceptions will be thrown. However, if you change the annotation back to @Configuration (using the defaults) and re-run the app you will get the following error:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: @Configuration class 'Config' contains overloaded @Bean methods with name 'upperCase'.
Use unique method names for separate bean definitions (with individual conditions etc) or switch '@Configuration.enforceUniqueMethods' to 'false'.
Offending resource: class path resource [com/codelearnhub/configurationAnnotation/configuration/Config.class]

5. Conclusion

By now you should be able to use @Configuration annotation in Spring Boot with or without changing the default attributes. You can find the source code on our GitHub page.

6. Sources

[1]: Bean (Spring Framework 5.3.19 API)

Related Posts