«1. Обзор

В этом руководстве мы обсудим язык выражений pointcut Spring AOP.

Сначала мы познакомимся с терминологией, используемой в аспектно-ориентированном программировании. Точка соединения — это шаг выполнения программы, такой как выполнение метода или обработка исключения. В Spring AOP точка соединения всегда представляет выполнение метода. Pointcut — это предикат, который соответствует точкам соединения, а язык выражений pointcut — это способ программного описания pointcut.

2. Использование

Выражение pointcut может появляться как значение аннотации @Pointcut:

@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryClassMethods() {}

Объявление метода называется сигнатурой pointcut. Он предоставляет имя, которое может использоваться аннотациями-советами для ссылки на этот pointcut.

@Around("repositoryClassMethods()")
public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
    ...
}

Выражение pointcut также может отображаться как значение свойства expression тега aop:pointcut:

<aop:config>
    <aop:pointcut id="anyDaoMethod" 
      expression="@target(org.springframework.stereotype.Repository)"/>
</aop:config>

3. Обозначения Pointcut

Выражение pointcut начинается с обозначения pointcut (PCD) , которое является ключевым словом, сообщающим Spring AOP, что следует сопоставлять. Существует несколько указателей pointcut, таких как выполнение метода, тип, аргументы метода или аннотации.

3.1 выполнение

Основным PCD Spring является выполнение, которое соответствует точкам соединения выполнения метода.

@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")

Этот пример pointcut будет точно соответствовать выполнению метода findById класса FooDao. Это работает, но не очень гибко. Предположим, мы хотим сопоставить все методы класса FooDao, которые могут иметь разные сигнатуры, типы возвращаемых значений и аргументы. Для этого мы можем использовать подстановочные знаки:

@Pointcut("execution(* com.baeldung.pointcutadvice.dao.FooDao.*(..))")

Здесь первый подстановочный знак соответствует любому возвращаемому значению, второй соответствует любому имени метода, а шаблон (..) соответствует любому количеству параметров (нулю или больше).

3.2 в пределах

Еще один способ добиться того же результата, что и в предыдущем разделе, — использовать внутри PCD, который ограничивает сопоставление точками соединения определенных типов.

@Pointcut("within(com.baeldung.pointcutadvice.dao.FooDao)")

Мы также можем сопоставить любой тип внутри пакета com.baeldung или подпакета.

@Pointcut("within(com.baeldung..*)")

3.3 this и target

this ограничивает сопоставление точками соединения, где ссылка на bean-компонент является экземпляром данного типа, в то время как target ограничивает сопоставление точками соединения, где целевой объект является экземпляром данного типа. Первый работает, когда Spring AOP создает прокси-сервер на основе CGLIB, а второй используется при создании прокси-сервера на основе JDK. Предположим, что целевой класс реализует интерфейс:

public class FooDao implements BarDao {
    ...
}

В этом случае Spring AOP будет использовать прокси-сервер на основе JDK, и вы должны использовать целевой PCD, потому что проксируемый объект будет экземпляром класса Proxy и реализует BarDao. interface:

@Pointcut("target(com.baeldung.pointcutadvice.dao.BarDao)")

С другой стороны, если FooDao не реализует какой-либо интерфейс или для свойства proxyTargetClass установлено значение true, то проксируемый объект будет подклассом FooDao, и можно будет использовать этот PCD:

@Pointcut("this(com.baeldung.pointcutadvice.dao.FooDao)")

~~ ~ 3.4 args

Этот PCD используется для сопоставления конкретных аргументов метода:

@Pointcut("execution(* *..find*(Long))")

Этот pointcut соответствует любому методу, который начинается с find и имеет только один параметр типа Long. Если мы хотим сопоставить метод с любым количеством параметров, но с первым параметром типа Long, мы могли бы использовать следующее выражение:

@Pointcut("execution(* *..find*(Long,..))")

3.5 @target

@target PCD (не путать с целевой PCD, описанный выше) ограничивает сопоставление точками соединения, где класс исполняемого объекта имеет аннотацию данного типа:

@Pointcut("@target(org.springframework.stereotype.Repository)")

3.6 @args

Этот PCD ограничивает сопоставление точками соединения, где тип среды выполнения фактически переданные аргументы имеют аннотации данного типа (типов). Предположим, что мы хотим отследить все методы, принимающие bean-компоненты, аннотированные аннотацией @Entity:

@Pointcut("@args(com.baeldung.pointcutadvice.annotations.Entity)")
public void methodsAcceptingEntities() {}

Чтобы получить доступ к аргументу, мы должны предоставить аргумент JoinPoint совету:

@Before("methodsAcceptingEntities()")
public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {
    logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]);
}

3.7 @within

Это PCD ограничивает сопоставление точками соединения в пределах типов, имеющих данную аннотацию:

@Pointcut("@within(org.springframework.stereotype.Repository)")

Что эквивалентно:

@Pointcut("within(@org.springframework.stereotype.Repository *)")

3.8 @annotation

Это PCD ограничивает сопоставление точками соединения, в которых субъект соединения точка имеет заданную аннотацию. Например, мы можем создать аннотацию @Loggable:

@Pointcut("@annotation(com.baeldung.pointcutadvice.annotations.Loggable)")
public void loggableMethods() {}

«

@Before("loggableMethods()")
public void logMethod(JoinPoint jp) {
    String methodName = jp.getSignature().getName();
    logger.info("Executing method: " + methodName);
}

«Затем мы можем зарегистрировать выполнение методов, отмеченных этой аннотацией:

4. Объединение выражений Pointcut

@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}

@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods() {}

@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods() {}

Выражения Pointcut можно комбинировать с помощью \u0026\u0026, || и ! операторы:

5. Заключение

В этом кратком введении в Spring AOP и pointcuts мы проиллюстрировали несколько примеров использования выражений pointcut.