Что такое проксирование объекта в Spring и зачем оно нужно
Что проверяют
Понимаете ли вы, что аннотации вроде @Transactional и @Cacheable работают через прокси, и знаете ли следствия этого механизма.
Как отвечать
Spring кладёт в контейнер не сам ваш объект, а обёртку вокруг него. Обёртка перехватывает вызов, делает своё (открывает транзакцию, читает кэш, проверяет права, пишет метрику) и передаёт управление настоящему объекту.
Два способа: динамический прокси JDK, если бин реализует интерфейс, и подкласс через CGLIB, если нет. Отсюда практическое требование: у класса не должно быть final на классе и на перехватываемых методах, иначе подкласс не создать.
Главное следствие: перехват работает только при вызове через прокси, то есть снаружи. Вызов метода изнутри того же объекта идёт напрямую:
public void outer() { this.inner(); } // @Transactional на inner не сработаетОтсюда же: аннотации на приватных и final методах бесполезны, а @Transactional на методе, вызванном из конструктора или из @PostConstruct, не действует, потому что прокси ещё не готов.
Лечится выносом метода в отдельный бин, инъекцией самого себя или включением AspectJ, который меняет байт-код и не зависит от прокси.
Где спотыкаются
Не знают про самовызов и часами ищут, почему транзакция не откатывается.
Ставят final на класс сервиса и получают ошибку создания бина.
Считают, что прокси создаётся для всех бинов. Только для тех, к которым применим хотя бы один аспект.
Не могут объяснить разницу между прокси JDK и CGLIB.