Dependency Injection (DI)
What DI means:
Provide an object's dependencies from the outside
instead of creating them inside the class.
DI is how IoC is implemented in Spring.
class A {
B b = new B();
}
class A {
private final B b;
public A(B b) {
this.b = b;
}
}
Types of DI
1) Constructor Injection (RECOMMENDED)
class MessageService {
public String getMessage() {
return "Hello DI";
}
}
class NotificationController {
private final MessageService messageService;
public NotificationController(MessageService messageService) {
this.messageService = messageService;
}
public void print() {
System.out.println(messageService.getMessage());
}
}
Best practice because:
- dependencies are required
- object is always valid
- easier to test
2) Field Injection (NOT recommended)
import org.springframework.beans.factory.annotation.Autowired;
class NotificationController {
@Autowired
private MessageService messageService;
public void print() {
System.out.println(messageService.getMessage());
}
}
Problems:
- hard to test
- hidden dependencies
- not immutable
IoC using DI
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
package com.example.di;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
OrderService service =
context.getBean(OrderService.class);
service.processOrder();
}
}
@Configuration
@ComponentScan(basePackages = "com.example.di")
class AppConfig {
}
@Service
class PaymentService {
public void pay() {
System.out.println("Payment executed ...");
}
}
@Service
class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder() {
paymentService.pay();
System.out.println("Order processed.");
}
}