Что такое dependency ingection?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Dependency Injection (DI)
Dependency Injection (внедрение зависимостей) — это паттерн проектирования, который решает проблему создания объектов и управления их зависимостями. Вместо того, чтобы объект сам создавал необходимые ему зависимости, они ему предоставляются извне (внедряются).
Основная идея
Объект не должен создавать объекты, от которых он зависит. Вместо этого, эти зависимости передаются конструктором, методом или через поле. Это делает код более модульным, тестируемым и гибким.
Три способа внедрения зависимостей
1. Constructor Injection (внедрение через конструктор) — самый рекомендуемый способ
// ДО: объект сам создаёт зависимость
public class UserService {
private UserRepository repository = new UserRepository();
public void saveUser(User user) {
repository.save(user);
}
}
// ПОСЛЕ: зависимость передаётся через конструктор
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public void saveUser(User user) {
repository.save(user);
}
}
2. Setter Injection (внедрение через setter)
public class UserService {
private UserRepository repository;
public void setRepository(UserRepository repository) {
this.repository = repository;
}
public void saveUser(User user) {
repository.save(user);
}
}
3. Interface Injection (внедрение через интерфейс)
public interface RepositoryAware {
void setRepository(UserRepository repository);
}
public class UserService implements RepositoryAware {
private UserRepository repository;
@Override
public void setRepository(UserRepository repository) {
this.repository = repository;
}
}
Spring и Dependency Injection
Spring IoC Container управляет созданием объектов (bean'ов) и их зависимостями. Разработчик только описывает, какие объекты нужны, а Spring сам их создаёт и внедряет.
Configuration через аннотации:
// Интерфейс
public interface UserRepository {
void save(User user);
}
// Реализация
@Repository
public class UserRepositoryImpl implements UserRepository {
@Override
public void save(User user) {
System.out.println("Сохраняю пользователя: " + user.getName());
}
}
// Service с внедрением
@Service
public class UserService {
private final UserRepository repository;
// Spring автоматически внедряет зависимость
@Autowired
public UserService(UserRepository repository) {
this.repository = repository;
}
public void createUser(String name) {
User user = new User(name);
repository.save(user);
}
}
// Использование в приложении
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
public void createUser(@RequestBody String name) {
userService.createUser(name);
}
}
Java Configuration
@Configuration
public class AppConfig {
// Определяем bean вручную
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
@Bean
public UserService userService(UserRepository repository) {
return new UserService(repository);
}
}
Преимущества Dependency Injection
Тестируемость — легко подменить реальные зависимости на mock'и в тестах:
@Test
public void testUserService() {
// Создаём mock
UserRepository mockRepository = Mockito.mock(UserRepository.class);
// Внедряем mock вместо реальной зависимости
UserService service = new UserService(mockRepository);
// Тестируем
service.createUser("Ivan");
Mockito.verify(mockRepository).save(Mockito.any(User.class));
}
Гибкость — можно легко переключаться между разными реализациями:
// Для production
@Configuration
public class ProdConfig {
@Bean
public UserRepository userRepository() {
return new DatabaseUserRepository();
}
}
// Для тестов
@Configuration
public class TestConfig {
@Bean
public UserRepository userRepository() {
return new InMemoryUserRepository();
}
}
Чистота кода — бизнес-логика отделена от логики создания объектов.
Слабая связанность — классы не зависят от конкретных реализаций, а от абстракций (интерфейсов).
Scope'ы bean'ов в Spring
- Singleton (по умолчанию) — один объект на всё приложение
- Prototype — новый объект при каждом запросе
- Request — новый объект на каждый HTTP запрос
- Session — новый объект на каждую сессию
@Component
@Scope("prototype")
public class PrototypeService {
// Новый объект каждый раз
}
Современный подход: @Autowired в конструктор
@Service
public class UserService {
private final UserRepository repository;
// @Autowired уже не требуется для конструктора с одним параметром
public UserService(UserRepository repository) {
this.repository = repository;
}
}
Dependency Injection — это фундаментальный паттерн современной Java-разработки, обеспечивающий гибкость, тестируемость и поддерживаемость кода.