How do you implement constructor-based dependency injection in Spring?

Table of Contents

Introduction

In Spring, dependency injection (DI) is a core concept that allows you to manage the dependencies of classes in a decoupled manner. Constructor-based dependency injection is one of the most commonly used approaches in Spring for injecting dependencies into a class. It involves passing dependencies to a class through its constructor when the bean is created.

This approach provides several advantages, such as immutability and easier unit testing. Constructor injection is preferred in cases where the injected dependencies are mandatory for the proper functioning of the class.

1. What is Constructor-Based Dependency Injection?

Constructor-based dependency injection works by providing the necessary dependencies to a class via its constructor. When Spring creates a bean, it calls the constructor of the class and passes the required dependencies as constructor arguments.

The main advantage of constructor injection is that it ensures immutability because the dependencies are set when the bean is created, and they cannot be changed afterward.

2. Using @Autowired with Constructor Injection

In Spring, the @Autowired annotation is used to automatically wire the required dependencies into a class. When constructor-based DI is used, @Autowired is placed on the constructor to let Spring know which dependencies to inject.

Example: Constructor-Based Dependency Injection

In this example:

  • MyService depends on MyRepository. The dependency is injected via the constructor.
  • The @Autowired annotation is used on the constructor of MyService. Spring automatically injects the required MyRepository bean into this constructor when it creates MyService.

3. How Constructor Injection Works in Spring

When Spring creates the MyService bean, it detects the constructor and looks for the required dependency MyRepository. It then instantiates MyRepository (if it has not already been created) and passes it to the constructor of MyService.

Spring automatically manages this process through its IoC (Inversion of Control) container, so the dependencies are injected without needing explicit configuration.

Example: Using @ComponentScan to Detect Components

To allow Spring to automatically detect these components, ensure that the Spring application is configured for component scanning. If you have multiple classes annotated with @Component, you can use @ComponentScan to automatically detect and register these beans.

4. Benefits of Constructor-Based Dependency Injection

  1. Immutability: Once the dependencies are injected, they cannot be changed, making the class more reliable and thread-safe.
  2. Required Dependencies: Constructor injection ensures that all necessary dependencies are provided at the time of object creation, avoiding the risk of uninitialized dependencies.
  3. Simpler to Unit Test: Constructor injection makes it easier to create mock dependencies during unit testing since the dependencies are explicitly passed through the constructor.
  4. Clear Dependencies: Constructor injection makes the class dependencies explicit, improving code readability and maintainability.

5. Autowiring by Type and Constructor Injection

When using constructor-based dependency injection, Spring can automatically inject the required beans by type. If multiple beans of the same type exist, you can use the @Qualifier annotation to specify which bean to inject.

Example: Autowiring by Type

In this case, MyRepository is automatically injected into MyService because Spring uses the type (MyRepository) to resolve the dependency.

Example: Using @Qualifier for Multiple Beans of the Same Type

If you have multiple beans of the same type, use the @Qualifier annotation to specify which one to inject:

Here, @Qualifier("myRepository1") is used to specify which MyRepository implementation to inject into MyService.

6. No @Autowired on Constructor in Spring 4.3+

Starting from Spring 4.3, if a class has only one constructor, Spring automatically uses it for dependency injection, even without the @Autowired annotation. The constructor is still required to be explicitly defined, but the @Autowired annotation is optional.

Example: Spring 4.3+ Constructor Injection Without @Autowired

7. Using Constructor Injection in XML Configuration (Optional)

While most modern Spring applications use annotations, constructor-based injection can also be configured using XML-based configuration. However, this is becoming less common with the prevalence of Java-based configuration.

Example: Constructor Injection in XML

In this XML configuration:

  • constructor-arg is used to specify the dependency that should be injected into the MyService bean’s constructor.

Conclusion

Constructor-based dependency injection in Spring is a robust and effective way to wire dependencies into your Spring beans. It provides immutability, ensures required dependencies are set during bean creation, and makes the class easier to test and maintain. By using @Autowired and constructors, you can leverage Spring's IoC container to manage your application's dependencies in a clean and structured way.

Constructor injection is highly recommended for mandatory dependencies that must be provided at the time of bean creation, helping maintain a clear and well-defined class structure.

Similar Questions