@Autowired Annotation in Spring Boot

1,160 views

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

1. What is @Autowired in Spring

@Autowired annotation allows you to inject a bean to a class (This is called Dependency Injection or DI for short). Additionally, @Autowired can be applied to each of the following:

  • A Constructor (@Autowired is optional since Spring 4.2)
  • A Setter
  • A Field
  • Parameter of a method

Constructor injection is much preferred for the following reasons:

  • Ensures that the reference of the bean will not change by setting it as final.
  • It is clear which mandatory dependencies each class has.
  • Enhances loose coupling

Furthermore, @Autowired has only one attribute, and that’s boolean required which defaults to true. We’ll see why and when we might need to set it to false

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 Service

Let’s create a dummy WordService under com.codelearnhub.autowiredinspring.service package as shown below:

package com.codelearnhub.autowiredinspring.service;

import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;

@Service
public class WordService {

    private final List<String> words = Arrays.asList("Code", "Learn", "Hub");

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

Here we just created a bean using the @Service annotation which will later be injected using @Autowired annotation.

4. Using @Autowired on Constructor

Now let’s create a new class WordConstructorDIController under com.codelearnhub.autowiredinspring.controller package:

package com.codelearnhub.autowiredinspring.controller;

import com.codelearnhub.autowiredinspring.service.WordService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class WordConstructorDIController {

    private final WordService wordService;

    // It works with or without @Autowired
    public WordConstructorDIController(WordService wordService) {
        this.wordService = wordService;
    }

    @GetMapping("/words")
    public List<String> getAll(){
        return wordService.getAllWords();
    }
}

Here we just created a Rest Controller and injected the WordService dependency by creating a member wordservice that is both private (since we do not need to be accessed anywhere but in this class) and final (since we do not want this object to be changed at all.

Again, note that in this special case, which is @Autowired applied to a constructor, we actually do not need this annotation since Spring 4.2.

As you can observe it is as clear as possible which dependencies this class has. Additionally, if we wanted to add another service to this class, let’s say a LetterService, we would add only the following:

private final WordService wordService;
private final LetterService letterService;
// It works with or without @Autowired
public WordConstructorDIController(WordService wordService, LetterService letterService) {
    this.wordService = wordService;
    this.letterService = letterService;
}

5. Using @Autowired on Setter

Before we create a class that will use @Autowired in a setter level, head to application.properties and add the following line:

spring.profiles.active=setter

Now head back to the controller that we previously created and add this line after @RestController:

@Profile("constructor")

This will allow us to not get errors even though 2 beans methods will exist with the same mapping.

Now create another class after the same package, as shown below:

package com.codelearnhub.autowiredinspring.controller;

import com.codelearnhub.autowiredinspring.service.WordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@Profile("setter")
public class WordSetterDIController {

    private WordService wordService;

    @Autowired
    public void setWordService(WordService wordService) {
        this.wordService = wordService;
    }

    @GetMapping("/words")
    public List<String> getAll(){
        return wordService.getAllWords();
    }
}

First of all, since we will use setters to inject our service bean, we are unable to set the bean as final (contrary to constructor injection). Also, now we are obliged to use the @Autowired annotation otherwise the object would be null.

6. Using @Autowired on Field

Before we create a class that will use @Autowired at a field level, head to application.properties and change the following line:

spring.profiles.active=field

Now create another class after the same package, as shown below:

package com.codelearnhub.autowiredinspring.controller;

import com.codelearnhub.autowiredinspring.service.WordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@Profile("field")
public class WordFieldDIController {

    @Autowired
    private WordService wordService;

    @GetMapping("/words")
    public List<String> getAll(){
        return wordService.getAllWords();
    }
}

As you can observe, in that case, we just add @Autowired on top of the bean that we want to inject. As before, we cannot set the bean as final, since we do not have any constructors and there is no way to ensure that this variable won’t change reference.

7. @Autowired in Method Parameters and Optional Autowiring

You can also use @Autowired in method parameters; first, change the line of application.properties to this:

spring.profiles.active=parameter

Then create a LetterService class under service package as shown below:

package com.codelearnhub.autowiredinspring.service;

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

public class LetterService {

    private final List<Character> letters = Arrays.asList('C', 'L', 'H');

    public List<Character> getAllLetters(){
        return letters;
    }

}

We won’t use any annotations for this class for now.

Then, create the following class under the controller package:

package com.codelearnhub.autowiredinspring.controller;

import com.codelearnhub.autowiredinspring.service.LetterService;
import com.codelearnhub.autowiredinspring.service.WordService;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@Profile("parameter")
public class WordParameterController {

    private final WordService wordService;
    private LetterService letterService;

    public WordParameterController(WordService wordService,
                                   LetterService letterService
    ) {
        this.wordService = wordService;
        this.letterService = letterService;
    }

    @GetMapping("/words")
    public List<String> getAll(){
        return wordService.getAllWords();
    }
}

As you can observe, we intend to have a mandatory wordService field and an optional field letterService. If we run the app, we’ll get an error:

Consider defining a bean of type 'com.codelearnhub.autowiredinspring.service.LetterService' in your configuration.

This is expected as we have not added the @Service to the LetterService class. However, you could actually make this bean optional, just by changing the constructor as shown below:

public WordParameterController(WordService wordService,
                               @Autowired(required = false) LetterService letterService
) {
    this.wordService = wordService;
    this.letterService = letterService;
}

Now if we run again the app, we won’t get any errors, even though we don’t have any bean of type LetterService, because we added the @Autowired(required = false).

This means that if for any reason the bean could not instantiate, the application will not fail.

Now if we head back to LetterService and add the @Service annotation on top, we would get our letterService bean initialized as expected.

8. Conclusion

By now you should know exactly how @Autowired annotation works and how you could optionally autowire a bean. You can find the source code on our GitHub page.

9. Sources

[1]: Autowired (Spring Framework 5.3.19 API)

Related Posts