Dependency Injection is a design pattern used to implement Inversion of Control (IoC) between classes and their dependencies. Instead of a class creating its dependencies, they are provided by an external source, typically a framework like Spring. This approach decouples the class from the details of its dependencies, allowing for more flexible and testable code.
In simpler terms, DI means that the Spring container manages the lifecycle and relationships between the objects in your application.
Let’s dive into how you can implement DI in a Spring Boot application.
Step 1: Setting Up a Spring Boot Application
First, create a new Spring Boot project using Spring Initializr (https://start.spring.io/) or your preferred IDE. Include the necessary dependencies, such as spring-boot-starter
.
Step 2: Defining Components and Services
Define the components and services in your application. For example, let’s create a simple service and a controller that depends on this service.
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class GreetingService {
public String greet() {
return "Hello, World!";
}
}
Step 3: Injecting Dependencies
Now, let’s inject the GreetingService
into a controller using different types of DI.
Constructor Injection
package com.example.demo.controller;
import com.example.demo.service.GreetingService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private final GreetingService greetingService;
public GreetingController(GreetingService greetingService) {
this.greetingService = greetingService;
}
@GetMapping("/greet")
public String greet() {
return greetingService.greet();
}
}
Setter Injection
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;
@RestController
public class GreetingController {
private GreetingService greetingService;
@Autowired
public void setGreetingService(GreetingService greetingService) {
this.greetingService = greetingService;
}
@GetMapping("/greet")
public String greet() {
return greetingService.greet();
}
}
Field Injection
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;
@RestController
public class GreetingController {
@Autowired
private GreetingService greetingService;
@GetMapping("/greet")
public String greet() {
return greetingService.greet();
}
}
While Spring supports all three types of dependency injection, constructor injection is generally recommended for mandatory dependencies as it ensures that the dependencies are provided at the time of object creation. Setter and field injections are more suitable for optional dependencies.
]]>