Constructor Injection
Constructor Injection Pattern
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentService paymentService;
private final NotificationService notificationService;
// All dependencies injected via constructor
public OrderService(OrderRepository orderRepository,
PaymentService paymentService,
NotificationService notificationService) {
this.orderRepository = orderRepository;
this.paymentService = paymentService;
this.notificationService = notificationService;
}
}
Benefits
| Benefit | Explanation |
|---|---|
| Immutability | Dependencies are final, can't change after construction |
| Explicit | All dependencies visible in constructor |
| Testable | Easy to pass mocks in unit tests |
| Null safety | Fails fast if dependency missing |
| No reflection | Works without Spring (POJO) |
Unit Testing
class OrderServiceTest {
@Test
void shouldCreateOrder() {
// Arrange — no Spring needed!
OrderRepository mockRepo = mock(OrderRepository.class);
PaymentService mockPayment = mock(PaymentService.class);
NotificationService mockNotification = mock(NotificationService.class);
OrderService service = new OrderService(mockRepo, mockPayment, mockNotification);
// Act
service.createOrder(new OrderRequest());
// Assert
verify(mockRepo).save(any());
}
}
Circular Dependencies
A depends on B
B depends on A
→ Circular dependency error at startup
Solutions:
- Redesign to break the cycle
- Use @Lazy annotation
- Extract shared logic to a third service
Best Practices
Key Principles
- Follow SOLID principles
- Write clean, readable code
- Test thoroughly
- Document decisions
- Monitor in production
Implementation
- Start simple, refactor as needed
- Use established patterns
- Consider trade-offs
- Review with peers
Continuous Improvement
- Learn from incidents
- Update documentation
- Share knowledge
- Mentor others
Key Points
- Understanding Constructor Injection is essential for production systems
- Always consider scalability and maintainability
- Test thoroughly before deploying to production
- Monitor performance and set up alerting
Common Patterns
- Validation: Always validate input at the boundary
- Error Handling: Use structured error responses
- Logging: Log key events for debugging
- Testing: Unit, integration, and load tests
- Documentation: Keep docs updated with code changes
Practice Problems
Design and implement a solution for Constructor Injection in a backend system. Consider scalability, error handling, and production readiness.
Solution
// Constructor Injection implementation
// Key aspects: validation, error handling, logging, testing
public class ConstructorInjection {
// Production-ready implementation
}Identify and handle edge cases for Constructor Injection. What happens under high load, with invalid input, or during failures?
Solution
// Edge case handling:
// 1. Null/empty input -> validation
// 2. High load -> rate limiting, queuing
// 3. Failures -> retries, circuit breaker
// 4. Concurrent access -> locks, idempotencyWrite a testing strategy for Constructor Injection. Include unit tests, integration tests, and performance tests.
Solution
// Test plan:
// - Unit: 80% coverage target
// - Integration: API contracts
// - Performance: latency, throughput
// - Chaos: failure injectionQuiz
1. What is the main benefit of constructor injection for testing?
2. What happens with circular dependency in Spring?
3. What is the primary purpose of Constructor Injection?
4. What is a common mistake when implementing Constructor Injection?
Flashcards
Question
Constructor injection benefits?
Click to reveal answer
Answer
Immutability, explicit dependencies, testable, null-safe
Question
How to fix circular dependency?
Click to reveal answer
Answer
Redesign, @Lazy, or extract shared logic to third service
Question
What is Constructor Injection?
Click to reveal answer
Answer
Constructor Injection is a key concept in backend development.
Question
When to use Constructor Injection?
Click to reveal answer
Answer
Use Constructor Injection when building production systems that require reliability, scalability, and maintainability.
Question
Constructor Injection best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Constructor injection: immutable, explicit, testable
- 2.All dependencies passed via constructor
- 3.Fails fast on missing dependencies
- 4.Avoid circular dependencies
Interview Tips
- •Explain why constructor injection is best
- •Know how to resolve circular dependencies
Cheat Sheet
Constructor Injection
- Pattern: final fields + constructor
- Benefits: Immutable, explicit, testable, null-safe
- Testing: Pass mocks directly, no Spring needed
- Circular deps: Redesign, @Lazy, or extract third service