Proper dependency management is required for building scalable and maintainable software applications. Dependency Injection (DI) is a design pattern that became popular in object-oriented programming languages. This method allows to build scalable, testable and maintainable systems.
What Is Dependency Injection (in Java)?
Dependency Injection is a design pattern used in object-oriented programming to make code more modular, testable, and maintainable. It’s a way to provide objects (dependencies) that a class needs from an external source, rather than having the class create them itself.
The Problem Without DI (Tight Coupling)
public class UserService {
private EmailService emailService;
public UserService() {
this.emailService = new EmailService(); // tight coupling
}
public void notifyUser(String message) {
emailService.sendEmail(message);
}
}
class EmailService {
public void sendEmail(String message) {
System.out.println("Sending email: " + message);
}
}
Issues:
- You can’t easily change EmailService to something else.
- You can’t unit test UserService without also testing EmailService.
Types of Dependency Injection
1. Constructor Injection
public class UserService {
private EmailService emailService;
public UserService(EmailService emailService) {
this.emailService = emailService; // injected dependency
}
public void notifyUser(String message) {
emailService.sendEmail(message);
}
}
class EmailService {
public void sendEmail(String message) {
System.out.println("Sending email: " + message);
}
}
Now we can inject the dependency externally:
public class Main {
public static void main(String[] args) {
EmailService emailService = new EmailService();
UserService userService = new UserService(emailService); // injecting dependency
userService.notifyUser("Welcome!");
}
}
1. Constructor Injection (most common)
Dependencies are passed through the constructor.
public class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
}
2. Setter Injection
Dependencies are set using public setter methods.
java
CopyEdit
public class Car {
private Engine engine;
public void setEngine(Engine engine) {
this.engine = engine;
}
}
3. Field Injection (with frameworks like Spring)
Framework injects directly into fields (usually using @Autowired).
public class Car {
@Autowired
private Engine engine;
}
Using Dependency Injection with Spring Framework
Spring handles DI for you using annotations like @Component, @Autowired, and @Service.
@Component
public class EmailService {
public void sendEmail(String message) {
System.out.println("Sending email: " + message);
}
}
@Service
public class UserService {
private final EmailService emailService;
@Autowired
public UserService(EmailService emailService) {
this.emailService = emailService;
}
public void notifyUser(String message) {
emailService.sendEmail(message);
}
}
And in the configuration:
@SpringBootApplication
public class App {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(App.class, args);
UserService userService = context.getBean(UserService.class);
userService.notifyUser("Welcome to Spring DI!");
}
}
0 Comments