← Назад к вопросам

Что такое dependency ingection?

2.3 Middle🔥 141 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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-разработки, обеспечивающий гибкость, тестируемость и поддерживаемость кода.