DEV Community

realNameHidden
realNameHidden

Posted on

What are the Different Ways @Autowired Annotation Can Be Used in Spring Boot?

Learn the different ways @Autowired annotation can be used in Spring Boot with practical Java 21 examples, best practices, REST APIs, cURL requests, and more.

What are the Different Ways @Autowired Annotation Can Be Used in Spring Boot?

If you're learning Spring Boot, you've probably seen the @Autowired annotation everywhere. But what exactly does it do? More importantly, what are the different ways @Autowired annotation can be used?

Think of a restaurant.

A waiter takes your order, but you never have to worry about finding the chef, the kitchen, or the ingredients. Everything is automatically connected behind the scenes.

Spring Boot works in a similar way.

Instead of manually creating objects using new, Spring automatically creates and injects them wherever they're needed. This process is called Dependency Injection (DI), and @Autowired is one of the most popular ways to achieve it.

In this article, you'll learn:

  • What @Autowired is
  • Different ways @Autowired annotation can be used
  • Which approach is recommended
  • Complete Java 21 examples
  • REST API example
  • cURL request and response
  • Best practices
  • Common mistakes beginners make

Whether you're just starting Java programming or looking to learn Java with Spring Boot, this guide will help you understand @Autowired with confidence.

What is @Autowired?

@Autowired is a Spring Framework annotation that tells the Spring IoC (Inversion of Control) container:

"Find an object (bean) of the required type and inject it automatically."

Without dependency injection:

UserService service = new UserService();
Enter fullscreen mode Exit fullscreen mode

With Spring:

@Autowired
private UserService service;
Enter fullscreen mode Exit fullscreen mode

Spring creates the object and injects it automatically.

Why Use @Autowired?

Using @Autowired offers several benefits:

  • Reduces boilerplate code
  • Encourages loose coupling
  • Improves maintainability
  • Makes unit testing easier
  • Lets Spring manage object lifecycles

Different Ways @Autowired Annotation Can Be Used

Spring supports multiple dependency injection techniques.

1. Constructor Injection (Recommended ✅)

Constructor injection is the recommended approach because:

  • Dependencies become mandatory.
  • Objects are immutable.
  • Easier to write unit tests.
  • Prevents partially initialized objects.

2. Field Injection

Spring injects the dependency directly into the field.

Although simple, it is not recommended for production code because:

  • Harder to test
  • Hidden dependencies
  • Doesn't encourage immutability

3. Setter Injection

Setter injection is useful when a dependency is optional or needs to change after object creation.

4. Method Injection

Spring can inject dependencies into any method annotated with @Autowired.

Useful for initialization logic.

5. Optional Dependencies

Spring supports optional dependencies using:

  • @Autowired(required = false)
  • Optional<T>
  • ObjectProvider<T>

The latter two are generally preferred in modern Spring applications because they make optionality explicit.

Complete End-to-End Example (Constructor Injection)

Project Structure

src
 └── main
      ├── java
      │     └── com.example.demo
      │            ├── DemoApplication.java
      │            ├── controller
      │            │      └── MessageController.java
      │            └── service
      │                   └── MessageService.java
      └── resources
             └── application.properties
Enter fullscreen mode Exit fullscreen mode

Code Example 1 – Constructor Injection (Recommended)

package com.example.demo.service;

import org.springframework.stereotype.Service;

/**
 * Service managed by Spring.
 */
@Service
public class MessageService {

    /**
     * Returns a welcome message.
     */
    public String getMessage() {
        return "Hello from Spring Boot using Constructor Injection!";
    }
}
Enter fullscreen mode Exit fullscreen mode
package com.example.demo.controller;

import com.example.demo.service.MessageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * REST Controller demonstrating constructor injection.
 */
@RestController
public class MessageController {

    private final MessageService messageService;

    /**
     * Spring automatically injects MessageService.
     * Since there is only one constructor,
     * @Autowired is optional in modern Spring.
     */
    public MessageController(MessageService messageService) {
        this.messageService = messageService;
    }

    @GetMapping("/message")
    public String message() {
        return messageService.getMessage();
    }
}
Enter fullscreen mode Exit fullscreen mode

Run the Application

./mvnw spring-boot:run
Enter fullscreen mode Exit fullscreen mode

or

mvn spring-boot:run
Enter fullscreen mode Exit fullscreen mode

Test the Endpoint

cURL

curl http://localhost:8080/message
Enter fullscreen mode Exit fullscreen mode

Response

Hello from Spring Boot using Constructor Injection!
Enter fullscreen mode Exit fullscreen mode

Code Example 2 – Setter Injection

package com.example.demo.service;

import org.springframework.stereotype.Service;

/**
 * Service managed by Spring.
 */
@Service
public class GreetingService {

    public String greeting() {
        return "Setter Injection Example";
    }
}
Enter fullscreen mode Exit fullscreen mode
package com.example.demo.controller;

import com.example.demo.service.GreetingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Demonstrates setter injection.
 */
@RestController
public class GreetingController {

    private GreetingService greetingService;

    /**
     * Spring injects GreetingService using this setter.
     */
    @Autowired
    public void setGreetingService(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GetMapping("/greeting")
    public String greeting() {
        return greetingService.greeting();
    }
}
Enter fullscreen mode Exit fullscreen mode

Test the Endpoint

cURL

curl http://localhost:8080/greeting
Enter fullscreen mode Exit fullscreen mode

Response

Setter Injection Example
Enter fullscreen mode Exit fullscreen mode

Constructor vs Field vs Setter Injection

Feature Constructor Field Setter
Recommended ✅ Yes ❌ No ✅ Sometimes
Immutable Dependencies
Easy Unit Testing
Mandatory Dependencies
Optional Dependencies

Best Practices

  1. Prefer constructor injection because it makes dependencies explicit and easier to test.
  2. Avoid field injection in production applications since it hides dependencies and complicates unit testing.
  3. Keep services focused by following the Single Responsibility Principle (SRP).
  4. Use Optional<T> or ObjectProvider<T> when a dependency is genuinely optional instead of relying on @Autowired(required = false).
  5. Annotate only Spring-managed components (such as @Service, @Component, @Repository, or @Controller) so Spring can create and inject them correctly.

Common Mistakes

  • Forgetting to annotate a class with @Service or @Component.
  • Creating objects manually using new instead of letting Spring manage them.
  • Using field injection everywhere because it's shorter.
  • Having multiple beans of the same type without resolving ambiguity using @Qualifier or @Primary.
  • Attempting to autowire classes that are not managed by the Spring container.

Helpful Resources

Conclusion

Understanding what are the different ways @Autowired annotation can be used is an essential step in mastering Spring Boot. While Spring offers constructor, field, setter, method, and optional dependency injection, constructor injection is the recommended approach because it improves readability, immutability, maintainability, and testability.

As you continue to learn Java and build real-world Java programming applications, you'll discover that proper dependency injection makes your code cleaner, more modular, and easier to maintain.

Try the examples in this guide, experiment with the different injection styles, and observe how Spring automatically wires your application's components together.

Call to Action

Have questions about @Autowired, Spring Boot, or dependency injection? Leave a comment below and share your experience. If there's another Java or Spring topic you'd like to explore, feel free to ask—happy coding!

Top comments (1)

Collapse
 
stitas profile image
stitas

Nice breakdown.

One thing I think would make the article even more useful is a small @Qualifier example. Multiple beans of the same type are one of the first confusing situations beginners are hit with when learning about dependency injection.

Spring needs to know which bean to choose.