Приходилось ли реализовывать аспекты самостоятельно?
Что проверяют
Писали ли вы аспект руками или только пользовались готовыми аннотациями. Главное, что хотят услышать: чем прокси отличается от полноценного вплетения байткода, потому что из этого следуют все ограничения.
Как отвечать
Сначала скажите, зачем понадобился свой аспект. Убедительные поводы: единый аудит вызовов, замер времени и счётчики, повтор по конкретному исключению, проверка прав по своей аннотации. Если задачу закрывают готовые аннотации транзакций, кэша или метрик, свой аспект не нужен, и это стоит проговорить.
Дальше устройство. Точку применения задавайте своей аннотацией, а не выражением по именам пакетов: аннотация переживает переезд классов.
@Aspect
@Component
public class AuditAspect {
@Around("@annotation(com.example.audit.Audited)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long started = System.nanoTime();
try {
return pjp.proceed();
} finally {
record(pjp.getSignature(), System.nanoTime() - started);
}
}
}Отдельно про механику: контейнер оборачивает бин прокси, поэтому перехватываются только вызовы, пришедшие через ссылку на бин. Когда нужно попасть в приватные методы, конструкторы или обращения к полям, берут вплетение во время компиляции или загрузки классов. Порядок нескольких аспектов задаётся явно.
Где спотыкаются
Самовызов. Метод того же класса зовёт аннотированный метод напрямую, вызов идёт мимо прокси, аспект молчит. Ровно так же не срабатывают транзакции, и это первое, что проверяют, когда «аннотация не работает». Лечится выносом в отдельный бин или переходом на вплетение байткода.
Пишут перехват вокруг вызова и теряют результат: забывают вернуть значение продолжения, глотают исключение, и метод молча отдаёт пустоту. Рядом другая беда: логируют аргументы целиком, а там пароли, токены и ленивые коллекции, обращение к которым дёргает базу прямо из аспекта.
Задают точку применения слишком широко. Аспект садится на все методы всех сервисов, включая геттеры в горячем цикле: стеки вызовов распухают, накладные расходы растут, а понять по коду, что на самом деле происходит при вызове, уже нельзя.