Код-ревью Middle IoC и внедрение зависимостей обновлено
Код-ревью: сервис уведомлений
Вопрос
Найдите проблемы с внедрением зависимостей и устройством бина.
@Service
public class NotificationService {
@Autowired
private UserRepository userRepository;
@Autowired
private ReportService reportService;
private EmailClient emailClient = new EmailClient("smtp.example.com", 25);
private static NotificationService instance;
@Autowired
public void init() {
instance = this;
}
public static NotificationService get() {
return instance;
}
public void notifyAll(String text) {
for (User u : userRepository.findAll()) {
emailClient.send(u.getEmail(), text);
}
reportService.markNotified();
}
}
Коротко
Главная мысль ревью: бин должен получать всё через конструктор, а внешние клиенты должны быть бинами со свойствами из конфигурации. Статический доступ к бину и захардкоженные адреса убивают тестируемость.
Что должен найти ревьюер
- Стильстрока 5Внедрение в поля: зависимости скрыты, поля не final, юнит-тест без Spring или рефлексии не написать. Лучше конструктор.
- Ошибкастрока 8Если ReportService тоже зависит от NotificationService, это цикл, который с Boot 2.6 роняет старт. Стоит проверить и развязать.
- Ошибкастрока 10EmailClient создаётся через new с захардкоженными хостом и портом: не управляется контейнером, не настраивается через свойства, не подменяется в тестах.
- Ошибкастрока 12Статическая ссылка на бин и метод get() это service locator в обход DI: ломает тесты и контексты (несколько контекстов перетирают instance).
- Производительностьстрока 24
findAll()грузит всех пользователей в память. Для рассылки нужна постраничная выборка или стриминг, а саму рассылку лучше делать асинхронно.
Разбор
Главная мысль ревью: бин должен получать всё через конструктор, а внешние клиенты должны быть бинами со свойствами из конфигурации. Статический доступ к бину и захардкоженные адреса убивают тестируемость. Отдельно стоит проверить зависимость ReportService на цикл и заменить findAll постраничной обработкой.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.