Short answer: constructor injection makes dependencies explicit, required and immutable, which is why the Spring team recommends it.
Advantages:
- Immutability: dependencies can be final, so they can't be changed after construction.
- Required dependencies are guaranteed: the object can't be created without them, so no NullPointerException from a missing injection.
- Easy testing: create the class with new OrderService(mockRepo, mockClock) in a plain unit test, with no Spring context or reflection.
- Design feedback: a constructor with seven parameters is a visible sign the class does too much.
- Circular dependencies fail fast at startup instead of being hidden.
- Works naturally with records and Lombok's @RequiredArgsConstructor.
No annotation needed: if a class has a single constructor, Spring uses it automatically; @Autowired is optional.
Field injection (@Autowired on a field):
- Shorter, but hides dependencies, prevents final, and needs reflection or a Spring context in tests.
Setter injection: fine for genuinely optional dependencies that have sensible defaults.