Код-ревью Middle AOP и прокси обновлено
Код-ревью: импорт товаров
Вопрос
Найдите проблемы, связанные с прокси и аннотациями.
@Service
public class ImportService {
private final ProductRepository repo;
private final PriceClient priceClient;
public ImportService(ProductRepository repo, PriceClient priceClient) {
this.repo = repo;
this.priceClient = priceClient;
}
public void importAll(List<ProductDto> items) {
for (ProductDto dto : items) {
importOne(dto);
}
notifyAdmins(items.size());
}
@Transactional
public void importOne(ProductDto dto) {
Product p = repo.save(new Product(dto.sku(), dto.name()));
p.setPrice(currentPrice(dto.sku()));
}
@Cacheable("prices")
public BigDecimal currentPrice(String sku) {
return priceClient.fetch(sku);
}
@Async
private void notifyAdmins(int count) {
log.info("imported {}", count);
}
@Transactional
public final void cleanup() {
repo.deleteDrafts();
}
}
Коротко
Все аннотации в этом классе молча не работают: вызовы через this, private и final методы прокси не перехватывает. Транзакционный импорт и кеш цен стоит вынести в отдельные бины (ProductImporter, PriceService), уведомление сделать публичным методом другого бина или событием с @Async-слушателем, а final убрать.
Что должен найти ревьюер
- Ошибкастрока 13importOne вызывается через this: @Transactional не сработает, каждый save идёт в своей авто-транзакции, изменение цены после save не сохранится (сущность не управляется).
- Производительностьстрока 21currentPrice вызывается через this: @Cacheable обходится, на каждый товар идёт внешний запрос за ценой.
- Ошибкастрока 30@Async на private-методе не работает (прокси его не видит), к тому же вызов через this: уведомление выполняется синхронно.
- Ошибкастрока 35final-метод не переопределяется CGLIB-прокси: транзакции нет, а вызов на прокси-объекте может упасть с NPE на repo.
- Производительностьстрока 19Даже если починить прокси, транзакция на каждый товар и внешний HTTP-вызов внутри транзакции держат соединение; лучше получить цены заранее пачкой.
Разбор
Все аннотации в этом классе молча не работают: вызовы через this, private и final методы прокси не перехватывает. Транзакционный импорт и кеш цен стоит вынести в отдельные бины (ProductImporter, PriceService), уведомление сделать публичным методом другого бина или событием с @Async-слушателем, а final убрать.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Предыдущий вопрос
@Transactional на private-методе
Следующий вопрос
Вызов @Transactional-метода из того же класса