Что произойдёт с @Transactional****, если метод объявлен в final-классе

Spring по умолчанию оборачивает бины в CGLIB-прокси — это подкласс вашего класса, который перехватывает вызов и открывает транзакцию до вызова реального метода. Подкласс не может унаследоваться от final-класса.

В Java с обычным классом это ошибка при старте контекста: Spring увидит аннотацию @Transactional, попытается создать прокси-наследника и упадёт на этапе создания бина с понятной ошибкой генерации класса.

С интерфейсными бинами Spring использует JDK-прокси и final на классе не мешает, потому что прокси реализует интерфейс, а не наследует класс. Проблема именно у CGLIB — когда прокси нужен поверх конкретного класса без интерфейса.

@Service public final class PaymentService {

@Transactional public void charge(Long orderId) { // CGLIB не создаст // прокси-наследника } }

Отдельно ловят на final-методе внутри обычного (не final) класса: класс можно унаследовать, а конкретный final-метод — нет, и CGLIB не сможет переопределить именно его. Транзакция тихо не применится, падения при старте не будет — это хуже, чем явная ошибка, потому что баг всплывает только в проде на реальных данных.

Проверка прокси-способности метода и класса — не теоретический вопрос: Kotlin-классы final по умолчанию, и та же ловушка там встречается в разы чаще.

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки