Dependency Inversion is a SOLID principle concerned with dependencies between layers.
Dependency Inversion Principle:
- High level modules should not depend upon low level modules. Both should depend upon abstractions.
- Abstractions should not depend upon details. Details should depend upon abstractions.
- Single Responsibility
- Open-Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
Dependency Injection solves an object instantiation problem arising from Dependency Inversion.
public class BookService {
private BookRepositoryH2 bookRepository;
public BookService() {
this.bookRepository = new BookRepositoryH2();
}
// ...
}
Dependency Inversion Refactoring: Replace a uses-relationship from layer A to layer B
with an implements-relationship from layer B to layer A.
public class BookService {
private BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
// ...
}
// ...
/* ... */ new BookService(new BookRepositoryH2()) /* ... */
Dependency Injection: Instead of instantiating your own dependencies,
accept your dependencies as constructor parameters.
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.CrudRepository;
@Repository
public interface BookRepository extends CrudRepository<Book, Long> {
}
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
// ...
}
Actually, constructor injection is preferred over @Autowired
for Service testing. Let's explore why...