Clean • Professional
Dependency Injection (DI) is a core concept of the Spring Framework. It allows the Spring IoC container to supply required dependencies to a class, instead of the class creating them itself. This results in loose coupling, better testability, and cleaner code.
Spring mainly supports three types of Dependency Injection.

Constructor Injection is a type of Dependency Injection where Spring provides required dependencies through the class constructor at the time of object creation.
final fieldsStep 1: Create a Dependency (PaymentService)
public interface PaymentService {
void pay();
}
Step 2: Provide an Implementation
import org.springframework.stereotype.Service;
@Service
public class CreditCardPaymentService implements PaymentService {
@Override
public void pay() {
System.out.println("Payment done using Credit Card");
}
}
Step 3: Inject Dependency Using Constructor Injection
import org.springframework.stereotype.Component;
@Component
public class OrderService {
private final PaymentService paymentService;
// @Autowired is optional (Spring 4.3+)
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder() {
paymentService.pay();
}
}
Step 4: Run the Application (Spring Boot)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ApplicationContext context =
SpringApplication.run(MyApplication.class, args);
OrderService orderService = context.getBean(OrderService.class);
orderService.processOrder();
}
}
Payment done using Credit Card
@Component / @ServiceOrderServicePaymentServiceCreditCardPaymentServicePaymentService bean firstOrderService constructorOrderService bean is created fully initialized➡️ If PaymentService is missing → Application fails to start
Setter Injection is a type of Dependency Injection where Spring injects dependencies via public setter methods after the object has been created.
It’s especially useful for optional dependencies or dependencies that may change during runtime.
null if the setter is not calledStep 1: Dependency Interface
public interface PaymentService {
void pay();
}
Step 2: Dependency Implementation
import org.springframework.stereotype.Service;
@Service
public class PaypalPaymentService implements PaymentService {
@Override
public void pay() {
System.out.println("Payment processed using PayPal");
}
}
Step 3: Service Using Setter Injection
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class OrderService {
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder() {
if(paymentService != null) {
paymentService.pay();
} else {
System.out.println("No payment service available");
}
}
}
Step 4: Main Application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ApplicationContext context =
SpringApplication.run(MyApplication.class, args);
OrderService orderService = context.getBean(OrderService.class);
orderService.processOrder();
}
}
@Autowired setter method.PaymentService bean (PaypalPaymentService).setPaymentService() to inject the dependency.OrderService bean is now fully initialized.If no matching PaymentService exists → paymentService may remain null. Always check in code or use @Required / Optional beans.
Field Injection is a type of Dependency Injection where Spring injects dependencies directly into the class fields using @Autowired, bypassing constructors or setter methods.
This method makes code shorter and quicker to write, but it comes with limitations.
Step 1: Dependency Interface
public interface PaymentService {
void pay();
}
Step 2: Implementation
import org.springframework.stereotype.Service;
@Service
public class PaypalPaymentService implements PaymentService {
@Override
public void pay() {
System.out.println("Payment processed using PayPal");
}
}
Step 3: Service with Field Injection
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class OrderService {
@Autowired
private PaymentService paymentService;
public void processOrder() {
paymentService.pay();
}
}
Step 4: Main Application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ApplicationContext context =
SpringApplication.run(MyApplication.class, args);
OrderService orderService = context.getBean(OrderService.class);
orderService.processOrder();
}
}
| Feature | Constructor Injection | Setter Injection | Field Injection |
|---|---|---|---|
| Mandatory Dependencies | Yes – ensures all required dependencies are provided at object creation | No – dependencies are optional | No – dependencies are hidden and optional |
| Optional Dependencies | No – strictly for mandatory dependencies | Yes – useful for optional or changeable dependencies | Yes – can be injected directly into fields |
| Immutability | Yes – makes the class immutable and safe | No – fields can be modified after object creation | No – fields are mutable and hidden |
| Testability | Easy – dependencies can be mocked in unit tests | Medium – requires setter setup for tests | Hard – difficult to inject mocks without reflection |
| Code Quality | High – clean, readable, and maintainable | Medium – readable but can be misused | Low – hidden dependencies, less maintainable |
| Recommended by Spring | Yes – preferred for mandatory dependencies | Sometimes – use for optional dependencies | No – discouraged in production-grade applications |
@RequiredArgsConstructor to reduce boilerplateSpring supports three types of Dependency Injection, but not all are equal.
👉 Choosing the correct injection type ensures your Spring Boot application is clean, testable, scalable, and production-ready.