Inversion of Control and Dependency Injection
In a plain Java program, LoanService would build what it needs itself: this.books = new BookRepository();. That looks harmless until a test wants a fake repository, or production wants one that talks to PostgreSQL instead of memory. The service has welded its own parts in. Spring flips this around.
The rule
Ask for what you need; never build it yourself.
Inversion of Control (IoC) is the big idea: your objects no longer control how their collaborators are created. The IoC container (Spring's application context) does. It reads your classes, creates one object per bean, and decides what goes where.
Dependency Injection (DI) is how the container delivers: it passes each object its dependencies from outside. The preferred form is constructor injection:
@Service
public class LoanService {
private final BookRepository books;
private final LoanProperties rules;
public LoanService(BookRepository books, LoanProperties rules) {
this.books = books;
this.rules = rules;
}
}LoanService only declares what it needs. At startup, the container sees the constructor, finds a BookRepository bean and a LoanProperties bean, and calls the constructor with them. When a class has exactly one constructor, no @Autowired is needed.
Two other forms exist. Field injection puts @Autowired on a field, and setter injection puts it on a setter. Both work, but a field-injected class cannot be created in a plain test without Spring, and its fields cannot be final. Prefer constructors.
What if two beans fit? If both JpaBookRepository and InMemoryBookRepository implement BookRepository, the container refuses to guess and startup fails. Mark one @Primary, or name the one you want with @Qualifier("inMemoryBookRepository") on the constructor parameter.
The shortcut
For every new inside a class, ask: "Is this a collaborator or a value?" A collaborator (repository, client, service) should be a constructor parameter. A value (a Loan, a LocalDate, a list) you still create with new.
Spot the new
this.books = new BookRepository();sits inside the constructor.
The failure you will meet most is No qualifying bean of type 'BookRepository' available. It means you asked for something nobody registered as a bean: a missing annotation, or a class outside the packages Spring scans.
Drills
Answer fast — trust the rule.
What does "Inversion of Control" mean in Spring?
Which injection style is recommended for required dependencies?
LoanService has a single constructor taking BookRepository. Does it need @Autowired?
Two beans implement BookRepository and LoanService asks for one. What happens with no extra hints?
Inside LoanService.borrow, which new is fine to keep?
Remember
- Ask for what you need; never build it yourself.
- For each
new, ask "collaborator or value?" Collaborators become constructor parameters. - Trap: two matching beans and no
@Primaryor@Qualifier— startup fails.
