Spring
Dependency Injection
Constructor Injection
Java
Annotations

Spring injects dependencies in constructor without Autowired annotation

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Spring Framework is renowned for its ability to simplify the management of application components and dependencies through its Inversion of Control (IoC) container. A common pattern in Spring applications is to use dependency injection to provide components and their dependencies. One often-used method in Spring is constructor-based injection, which can be performed without explicitly using the @Autowired annotation. In this article, we'll explore how Spring’s IoC container can automatically handle constructor injection, delve into an example, and examine the implications of this approach.

Constructor-Based Dependency Injection in Spring

Constructor-based dependency injection is a technique where dependencies are provided to a class via its constructor. This pattern ensures that a class is instantiated with all its required dependencies, enforcing immutability and promoting testability by leveraging dependency inversion.

Injecting Dependencies without @Autowired

In Spring, constructor-based injection can work without using the @Autowired annotation. By default, when a class has a single constructor, Spring's IoC container will automatically use this constructor to inject dependencies. The @Autowired annotation becomes implicit in this scenario.

How Spring Resolves Constructor Injection

When Spring is initialized and scans for components, it uses reflection to inspect available classes. Upon encountering classes with a single constructor, it automatically resolves the required dependencies by matching them against beans declared in the context. If multiple beans can satisfy a dependency and are not explicitly disambiguated, Spring will raise an exception.

Example

Consider an application with a MessageService and a Client class:

java
1@Component
2public class MessageService {
3    public String getMessage() {
4        return "Hello, World!";
5    }
6}
7
8@Component
9public class Client {
10
11    private final MessageService messageService;
12
13    // Note the absence of the @Autowired annotation
14    public Client(MessageService messageService) {
15        this.messageService = messageService;
16    }
17
18    public void showMessage() {
19        System.out.println(messageService.getMessage());
20    }
21}

In the above code, the Client component relies on MessageService. The constructor of Client receives the MessageService as a dependency. Since there is only one constructor in the Client class, Spring will autowire MessageService directly without the need for @Autowired.

Benefits of Constructor-Based Injection

  • Immutability: Dependencies are set at object instantiation time and cannot change, leading to immutable objects.
  • Testability: Constructor injection naturally supports mocking or stubbing of dependencies for unit testing.
  • Simplicity: Reduces boilerplate code by avoiding the @Autowired annotation in straightforward scenarios.

Handling Multiple Constructors

When a class has more than one constructor, Spring does not automatically know which one to use. In such cases, @Autowired can be used to indicate the preferred constructor:

java
1@Component
2public class MultiConstructorClient {
3
4    private final MessageService messageService;
5
6    @Autowired
7    public MultiConstructorClient(MessageService messageService) {
8        this.messageService = messageService;
9    }
10    
11    public MultiConstructorClient() {
12        this.messageService = null;
13    }
14}

Key Considerations

  1. Single vs Multiple Constructors: Automatic injection without @Autowired only works for classes with a single constructor.
  2. Required Dependencies: Ensure that the required beans are available in the application context, or else NoSuchBeanDefinitionException will be raised.
  3. Clearer Intent: Leveraging constructor injection clarifies the mandatory dependencies of a class.
  4. Circular Dependencies: Constructor injection cannot be used to create circular references between beans. Setter injection or field injection might be necessary in such cases.

Table Summary

AspectDescription
Automatic WiringWorks with a single constructor; no need for @Autowired.
ImmutabilityPromotes immutable objects by setting dependencies at construction time.
Enhanced TestabilityFacilitates unit testing by allowing easy mocking or stubbing of dependencies.
Multiple Constructors@Autowired or other methods must specify the constructor to use when more than one constructor is present.
Contextual RequirementsAll constructor dependencies must be present as beans in the Spring context.
No Circular DependenciesNot suitable for circular dependencies—consider using other injection methods in such cases.

Additional Considerations

  • Configuration: Ensure all component classes are appropriately annotated or defined in configuration classes for Spring to discover them.
  • Migration: Existing projects using different wiring configurations (XML, setter injection) can incrementally migrate to constructor injection for components where feasible.

In conclusion, Spring's capability to inject dependencies via a class's constructor, even without @Autowired, simplifies configuration and enhances the robustness of applications. This design enforces constructor injection, favoring component immutability and laying a strong foundation for modular, maintainable codebases. Understanding the nuances of this approach can be advantageous for developers aiming to leverage Spring's IoC container effectively.


Course illustration
Course illustration

All Rights Reserved.