Что такое Spring AOP (Aspect-Oriented Programming)? Какую проблему он решает?
Spring AOP позволяет выносить сквозную логику (логирование, транзакции, безопасность) в отдельные аспекты вместо её дублирования в каждом методе. Работает через прокси-объекты на основе JDK Dynamic Proxy или CGLIB.
Spring AOP: назначение и концепция
AOP (Aspect-Oriented Programming) — парадигма, дополняющая ООП для решения задач сквозной функциональности (cross-cutting concerns): логирования, аудита, транзакционности, кэширования, проверки прав доступа. Без AOP такая логика дублируется во множестве методов, нарушая принцип единственной ответственности.
Spring AOP реализует подмножество полноценного AspectJ через прокси: при запросе бина из контекста возвращается прокси-объект, перехватывающий вызовы методов.
Ключевые термины
- Aspect — модуль, инкапсулирующий сквозную логику (
@Aspect) - Advice — конкретный код, выполняемый в точке соединения:
@Before,@After,@AfterReturning,@AfterThrowing,@Around - Pointcut — выражение, определяющее, к каким методам применяется advice
- Join Point — конкретное место выполнения (в Spring AOP — всегда вызов метода)
- Weaving — процесс применения аспектов к целевому объекту (в Spring — во время создания прокси)
Пример: аспект для логирования времени выполнения
@Aspect
@Component
public class ExecutionTimeAspect {
private static final Logger log = LoggerFactory.getLogger(ExecutionTimeAspect.class);
// Все public-методы в пакете com.example.service
@Pointcut("execution(public * com.example.service..*(..))")
public void serviceMethods() {}
@Around("serviceMethods()")
public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed(); // вызов реального метода
} finally {
long elapsed = System.currentTimeMillis() - start;
log.info("{} executed in {} ms",
pjp.getSignature().toShortString(), elapsed);
}
}
}
Пример: аспект аудита через аннотацию
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audited {
String action();
}
@Aspect
@Component
public class AuditAspect {
@AfterReturning("@annotation(audited)")
public void audit(JoinPoint jp, Audited audited) {
System.out.printf("Action '%s' called on %s%n",
audited.action(), jp.getTarget().getClass().getSimpleName());
}
}
// Использование:
@Audited(action = "DELETE_USER")
public void deleteUser(Long id) { /* ... */ }
Включение AOP
@Configuration
@EnableAspectJAutoProxy // создаёт прокси для @Aspect-бинов
public class AopConfig {}
В Spring Boot достаточно зависимости spring-boot-starter-aop — @EnableAspectJAutoProxy подключается автоматически.
Подводные камни
- Прокси-ограничение: вызов метода внутри того же бина (self-invocation) не проходит через прокси и аспект не применяется. Обходное решение — инжектировать сам бин через контекст или использовать AspectJ weaving.
- Spring AOP работает только с Spring-бинами — аспекты не применяются к объектам, созданным через
new. @Aroundadvice обязан вызватьpjp.proceed(), иначе реальный метод никогда не выполнится.- JDK Dynamic Proxy применяется только к интерфейсам; для классов без интерфейса Spring переключается на CGLIB (который требует ненулевого конструктора).
- Порядок применения нескольких аспектов к одному методу не детерминирован без явного указания
@Order. - Pointcut-выражения компилируются при старте контекста — синтаксическая ошибка в выражении вызывает
IllegalArgumentException. - AspectJ-аннотации доступны через зависимость
aspectjweaver, но полноценный compile-time/load-time weaving AspectJ требует отдельной конфигурации Maven/Gradle плагина.
Common mistakes
- Путать термин «spring aop purpose» с соседним механизмом Spring Framework.
- Не называть границу lifecycle, transaction, thread или request для «spring aop purpose».
- Игнорировать production-эффекты «spring aop purpose»: latency, SQL shape, memory, security или observability.
What the interviewer is testing
- Попросить объяснить механизм «spring aop purpose» на минимальном примере.
- Проверить, видит ли кандидат failure mode и диагностику для «spring aop purpose».
- Уточнить, какие настройки или API меняют «spring aop purpose» в реальном сервисе.