In Spring Boot (and Spring Framework in general), Inversion of Control (IoC) and Dependency Injection (DI) are core concepts that simplify the development of loosely coupled, testable, and maintainable applications. Here’s a detailed explanation of both:
IoC is a design principle where the control of object creation, configuration, and lifecycle management is transferred from the developer to a container or framework.
- In traditional programming, the developer writes the code to create and manage objects. This leads to tightly coupled code, making it harder to test or change dependencies.
- With IoC, the Spring IoC container takes responsibility for creating and managing the dependencies between objects.
Instead of a class creating its dependencies directly using new
, the container injects the required dependencies into the class.
DI is a specific way to achieve IoC by injecting dependencies into a class instead of the class creating them itself. This is done by the Spring IoC container.
- Constructor Injection: The dependencies are provided through the class constructor.
- Setter Injection: The dependencies are injected through public setter methods.
- Field Injection: Dependencies are injected directly into fields using annotations like
@Autowired
.
@Component
and@Service
: Marks a class as a bean (managed by Spring IoC container).@Autowired
: Enables Spring to resolve and inject the bean.@Configuration
: Indicates a class that declares one or more@Bean
methods.@Bean
: Used to define a bean explicitly in Java-based configuration.@Controller
and@RestController
: Specialized annotations to mark classes that handle web requests.
public class UserService {
private UserRepository userRepository = new UserRepository();
public void performAction() {
userRepository.save();
}
}
In this case, the UserService
class directly creates an instance of UserRepository
, making it tightly coupled.
// UserRepository.java
@Component
public class UserRepository {
public void save() {
System.out.println("User saved!");
}
}
// UserService.java
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired // Constructor Injection
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void performAction() {
userRepository.save();
}
}
// Main Application
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@Component
marksUserRepository
as a Spring-managed bean.@Service
marksUserService
as a service layer bean.@Autowired
in the constructor tells Spring to inject an instance ofUserRepository
intoUserService
.
- Loose Coupling: Classes are not responsible for managing their dependencies.
- Testability: Mock dependencies can be easily injected during testing.
- Readability and Maintainability: Dependency management is centralized.
- Reusability: Beans can be reused across different parts of the application.
In short, IoC gives the framework control over object creation and lifecycle, while DI provides a way to supply the necessary dependencies to objects, enabling flexible and modular design.