Stop Using @Autowired! The Better Way to Inject Dependencies in Spring Boot 3

Daniel Angel
3 min read6 days ago

--

Since Spring Boot 3 and Spring Framework 6, the use of @Autowired for dependency injection has been discouraged. Instead, Spring recommends using constructor-based dependency injection. But why this change, and what is the best way to inject dependencies now? Let's explore it.

Photo by Markus Spiske on Unsplash

What is @Autowired?

Before discussing why Spring no longer recommends @Autowired, let's quickly review its purpose. @Autowired is used to inject dependencies into a class. It can be applied to:

  • Fields
  • Constructors
  • Setter methods

This allows Spring to automatically resolve and assign the required beans when the application starts.

Classic example of @Autowired in a field:

@Service
public class MyService {
@Autowired
private MyRepository myRepository;
}

In this case, Spring injects an instance of MyRepository when creating MyService. While this works, it has several drawbacks, especially in larger, more complex applications.

Why Doesn’t Spring Recommend @Autowired Anymore?

1. Encourages Immutable Dependencies

When we use @Autowired on fields, dependencies can accidentally be modified within the class, which goes against the principle of immutability. In contrast, constructor injection ensures that dependencies are assigned only once during bean creation.

2. Facilitates Unit Testing

Using constructor injection makes it much easier to provide mock dependencies for unit testing, as they can be explicitly passed into the constructor without needing Spring.

Example with @Autowired:

public class MyServiceTest {
@InjectMocks
private MyService myService;

@Mock
private MyRepository myRepository;

@BeforeEach
void setup() {
MockitoAnnotations.openMocks(this);
}
}

Example with constructor injection (no need for @InjectMocks):

public class MyServiceTest {
private MyService myService;

@Mock
private MyRepository myRepository;

@BeforeEach
void setup() {
myService = new MyService(myRepository);
}
}

3. Avoids Reflection Issues

When @Autowired is used on private fields, Spring uses reflection to inject dependencies, which can impact performance and code clarity. Constructor injection is a cleaner and more efficient alternative.

The New Recommended Approach: Constructor Injection

In Spring Boot 3, the best practice is to inject dependencies via constructors and omit @Autowired, as Spring implicitly applies it in classes with a single constructor.

Example:

@Service
public class MyService {
private final MyRepository myRepository;

public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}

Benefits of this approach:

  • Immutability: myRepository is final, preventing accidental reassignments.
  • Readability: The code explicitly states its dependencies.
  • Easy to test: Mocks can be passed without additional tools.

Exception: Multiple Optional Dependencies

If a dependency is optional, @Autowired can still be used in the constructor along with @Nullable or Optional:

@Service
public class MyService {
private final MyRepository myRepository;
private final Optional<AuditService> auditService;

@Autowired
public MyService(MyRepository myRepository, @Nullable AuditService auditService) {
this.myRepository = myRepository;
this.auditService = Optional.ofNullable(auditService);
}
}

Conclusion

Spring Boot 3 and Spring Framework 6 have made an effort to improve security, testability, and code clarity by promoting constructor-based dependency injection instead of @Autowired on fields. This change not only enhances immutability but also simplifies unit testing and improves application performance.

If you’re still using @Autowired on fields, now is a great time to migrate to constructor injection and take advantage of modern Spring best practices.

--

--

Daniel Angel
Daniel Angel

Written by Daniel Angel

Backend developer | Java, Spring boot, Cloud| Laravel, Php

No responses yet