Join Points

Давайте представим себе театральную постановку. У вас есть актёры, декорации, освещение и множество других элементов, которые работают вместе, чтобы создать потрясающее представление. Но иногда режиссёру нужно сделать корректировки: изменить момент входа актёра на сцену или добавить эффекты освещения в определенный момент. Эти моменты, когда режиссёру нужно вмешаться, можно сравнить с “Join Points” в мире Spring AOP


Что такое Join Points?

Join Point в Spring AOP — это место в программе, где аспект может быть применен. Это может быть при вызове метода, при обработке исключения, при инициализации объекта и так далее. Join Points обозначают конкретные моменты в выполнении программы, когда можно “вмешаться” с помощью аспектов.


Каковы основные типы Join Points?

Несмотря на то что в теории может существовать множество различных Join Points, в Spring AOP мы обычно имеем дело с вызовами методов. Это означает, что наиболее распространенным типом Join Point является момент, когда метод вызывается.


Почему это важно?

Понимание Join Points критически важно для успешного применения AOP. Это как если бы режиссёр театральной постановки не знал, когда актёры входят на сцену или когда происходят ключевые моменты действия. Если вы не знаете, где находятся ваши Join Points, вы не сможете эффективно применять ваши аспекты. 


Аналогия с книгой

Представьте, что ваше приложение — это книга. Каждая глава книги — это определенный функционал вашего приложения, а каждый абзац — это метод. Join Points в этой аналогии будут ключевыми словами или фразами, которые вы хотите выделить или комментировать. Когда вы найдете такое ключевое слово (Join Point), вы можете добавить примечание или комментарий (Advice) в этом месте. Join Points — это основа AOP. Они указывают, где и когда ваши аспекты будут применяться, давая вам возможность модифицировать или улучшать функциональность вашего приложения.


Практика использования Join Points

Подойдём к этому делу практически! Вспомним, что Join Points — это конкретные точки в вашем коде, где аспект может “вмешаться”. Самый популярный тип Join Point в Spring AOP — это вызов метода. Давайте разберём это на примерах.


Определение Join Points

Для того чтобы определить, где именно ваш аспект должен “вступать в игру”, вы используете выражения Pointcut. Эти выражения позволяют вам выбирать, на какие методы, классы или даже пакеты должен реагировать ваш аспект.

Пример 1: Применение аспекта ко всем методам в классе 

@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.service.MyService.*(..))")
public void beforeAnyMethodInMyService() {
System.out.println("Вызван метод в MyService!");
}
}

В данном примере execution(* com.example.service.MyService.*(..)) — это Pointcut выражение. Оно говорит Spring AOP применить аспект перед выполнением любого метода (.*(..)) в классе MyService


Пример 2: Применение аспекта ко всем методам в пакете

@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeAnyMethodInServicePackage() {
System.out.println("Вызван метод в пакете service!");
}
}

Здесь мы расширили наш Pointcut так, чтобы он реагировал на любой метод в любом классе в пакете service

Пример 3: Применение аспекта к конкретным методам

@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.service.MyService.specificMethod(..))")
public void beforeSpecificMethod() {
System.out.println("Вызван конкретный метод specificMethod!");
}
}

В этом примере мы уточнили наш Pointcut, чтобы реагировать только на вызов метода specificMethod в классе MyService.

Использование Join Points через Pointcut выражения дает вам мощные инструменты для контроля над тем, где и когда ваши аспекты будут применяться. Это позволяет уточнять поведение вашего приложения, добавляя дополнительную функциональность там, где это необходимо. 


Pointcut Expressions

Если вспомнить наш театральный пример, то Pointcut Expressions — это как режиссёрская инструкция: “Актёр А входит на сцену после фразы ‘Все было потеряно’”. Это уточнение показывает, когда именно должен произойти какой-то конкретный момент. 

В мире Spring AOP Pointcut Expressions позволяют вам точно определить, на какие методы, классы или даже пакеты будет реагировать ваш аспект. Они являются частью магии AOP и предоставляют мощные инструменты для уточнения поведения вашего кода. 


Структура Pointcut Expressions

Базовый формат Pointcut выглядит так:

execution(модификатор_доступа возвращаемый_тип имя_пакета.имя_класса.имя_метода(параметры))

Но большинство частей в этом формате являются опциональными. Давайте разберемся!


Пример 1: Выбор всех методов 

@Pointcut("execution(* *.*(..))")
private void selectAllMethods() {}


Пример 2: Выбор методов по имени

@Pointcut("execution(* *.set*(..))")
private void selectAllSetters() {}


Пример 3: Выбор методов по параметрам 

@Pointcut("execution(* *.find*(String))")
private void selectAllStringFinders() {}


Дополнительные Pointcut выражения

Pointcut не ограничивается только модификатором execution. Есть и другие, например:

• within(): ограничивает матчинг методов в определенных классах или пакетах. 

@Pointcut("within(com.example.service.*)")
private void allMethodsInService() {}


• this(): ограничивает матчинг методов, где прокси-объект имеет заданный тип.

• target(): ограничивает матчинг методов, где целевой объект (реальный объект, а не прокси) имеет заданный тип.

• args(): ограничивает матчинг методов, где аргументы имеют заданные типы. 

@Pointcut("args(String,..)")
private void methodsWithStringFirstArg() {}


• @annotation(): реагирует на методы, которые имеют определенную аннотацию. 

@Pointcut("@annotation(com.example.annotations.MyCustomAnnotation)")
private void methodsWithMyCustomAnnotation() {}

С помощью Pointcut Expressions у вас появляется гибкий и мощный инструмент, позволяющий детально контролировать, где именно будет применяться ваш аспект. Это позволяет вам создавать более чистый и модульный код, избегая повторений и улучшая читаемость.