Слайд 2План
Pointcut
Комбинирование Pointcut
Порядок выполнения Aspect-ов
![План Pointcut Комбинирование Pointcut Порядок выполнения Aspect-ов](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-1.jpg)
Слайд 3Pointcut
Pointcut – выражение, описывающее, где должен быть применен Advice.
Spring AOP использует AspectJ
![Pointcut Pointcut – выражение, описывающее, где должен быть применен Advice. Spring AOP](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-2.jpg)
Pointcut expression language, то есть определенные правила в написании выражений для создания Pointcut.
Слайд 4Pointcut
Для описания Pointcut используется шаблон. Выделены обязательные элементы.
execution( modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(parameters-pattern)
![Pointcut Для описания Pointcut используется шаблон. Выделены обязательные элементы. execution( modifiers-pattern? return-type-pattern](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-3.jpg)
throws-pattern? )
Под шаблон может подходить один или несколько методов, в зависимости от того, насколько детально был описан шаблон.
Слайд 5Pointcut
Рассмотрим пример с предыдущей лекции.
По шаблону мы указали все, кроме declaring-type-pattern и
![Pointcut Рассмотрим пример с предыдущей лекции. По шаблону мы указали все, кроме](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-4.jpg)
throws-pattern. Отсутствие declaring-type-pattern означает, что под шаблон подойдет метод getBook() абсолютно любого класса.
Слайд 6Pointcut
Создадим абстрактный класс
от которого будет наследоваться класс Library
![Pointcut Создадим абстрактный класс от которого будет наследоваться класс Library](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-5.jpg)
Слайд 7Pointcut
Переименуем класс, чтобы его название конкретизировало его природу. Например, в университетскую библиотеку.
Создадим
![Pointcut Переименуем класс, чтобы его название конкретизировало его природу. Например, в университетскую](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-6.jpg)
класс школьная библиотека.
Как вы можете видеть, под шаблон подходит оба метода.
Слайд 8Pointcut
Вызовем метод в классе Test1
![Pointcut Вызовем метод в классе Test1](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-7.jpg)
Слайд 9Pointcut
Вывод:
Это произошло, поскольку оба метода подходят под Pointcut.
![Pointcut Вывод: Это произошло, поскольку оба метода подходят под Pointcut.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-8.jpg)
Слайд 10Pointcut
Модифицируем Pointcut, чтобы метод вызвался только для UniLibrary. Для этого нам необходимо
![Pointcut Модифицируем Pointcut, чтобы метод вызвался только для UniLibrary. Для этого нам](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-9.jpg)
указать declaring-type-pattern, а именно полное имя класса UniLibrary.
Вывод:
Слайд 11Pointcut
execution(public void getBook()) – соответствует методу без параметров, где бы он ни
![Pointcut execution(public void getBook()) – соответствует методу без параметров, где бы он](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-10.jpg)
находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(public void com.donnu.demo.aop.UniLibrary.getBook()) – соответствует методу без параметров, из класса UniLibrary, с модификатором доступа public, возвращаемым типом void и названием getBook()
Слайд 12Pointcut
execution(public void get*()) – соответствует методу без параметров, где бы он ни
![Pointcut execution(public void get*()) – соответствует методу без параметров, где бы он](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-11.jpg)
находился, с модификатором доступа public, возвращаемым типом void и названием, начинающимся на get.
Слайд 13Pointcut
Добавим метод getMagazine в UniLibrary.
![Pointcut Добавим метод getMagazine в UniLibrary.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-12.jpg)
Слайд 14Pointcut
Добавим вызов метода getMagazine в Test1.
![Pointcut Добавим вызов метода getMagazine в Test1.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-13.jpg)
Слайд 15Pointcut
Как мы можем видеть аспект был вызван трижды. Для getBook и getMagazine
![Pointcut Как мы можем видеть аспект был вызван трижды. Для getBook и](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-14.jpg)
из UniLibrary и getBook из SchoolLibrary. Все эти методы подошли под шаблон.
Слайд 16Pointcut
Приведем пример работы с return-type-pattern. Добавим еще один Advice:
и метод в UniLibrary:
![Pointcut Приведем пример работы с return-type-pattern. Добавим еще один Advice: и метод в UniLibrary:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-15.jpg)
Слайд 17Pointcut
В классе Test1 вызовем метод returnBook:
Вывод указывает на то, что Advice работает:
![Pointcut В классе Test1 вызовем метод returnBook: Вывод указывает на то, что Advice работает:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-16.jpg)
Слайд 18Pointcut
Теперь, если мы изменим возвращаемый тип, например вот так:
Метод больше не будет
![Pointcut Теперь, если мы изменим возвращаемый тип, например вот так: Метод больше](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-17.jpg)
подходить под шаблон, Advice не будет вызван. Если же мы не хотим зависеть от возвращаемого типа, а он является обязательным параметром шаблона, мы можем изменить возвращаемый тип на *:
Слайд 19Pointcut
Если мы хотим аналогичным образом поступить с модификатором доступа, мы можем просто
![Pointcut Если мы хотим аналогичным образом поступить с модификатором доступа, мы можем](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-18.jpg)
его убрать, оставив только *.
Как вы помните modifiers-pattern не является обязательным элементом шаблона.
Слайд 20Pointcut
Таким образом:
execution(* returnBook()) - соответствует методу без параметров, где бы он ни
![Pointcut Таким образом: execution(* returnBook()) - соответствует методу без параметров, где бы](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-19.jpg)
находился, с любым модификатором доступа, любым возвращаемым типом и названием returnBook()
execution(* *()) - соответствует методу без параметров, где бы он ни находился, с любым модификатором доступа, любым возвращаемым типом и любым называнием
Слайд 21Pointcut
Рассмотрим параметры метода при написании Pointcut. Для этого вернем класс UniLibrary в
![Pointcut Рассмотрим параметры метода при написании Pointcut. Для этого вернем класс UniLibrary](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-20.jpg)
первоначальное состояние.
Это необходимо для более простой работы с добавлением параметров.
Слайд 22Pointcut
Добавим параметр в метод getBook
В Test1 добавим параметр при вызове метода
Убедимся, что
![Pointcut Добавим параметр в метод getBook В Test1 добавим параметр при вызове](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-21.jpg)
при этом наш Advice больше не срабатывает
Слайд 23Pointcut
Добавим параметр в Advice. Обратите внимание, что указывается только тип параметра, но
![Pointcut Добавим параметр в Advice. Обратите внимание, что указывается только тип параметра,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-22.jpg)
не его название.
Вывод:
Слайд 24Pointcut
execution(public void getBook(String)) - соответствует методу с параметром String, где бы он
![Pointcut execution(public void getBook(String)) - соответствует методу с параметром String, где бы](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-23.jpg)
ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
Слайд 25Pointcut
Допустим, что мы хотим, чтобы под наш шаблон подходил любой метод, имеющий
![Pointcut Допустим, что мы хотим, чтобы под наш шаблон подходил любой метод,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-24.jpg)
только 1 параметр. Для этого добавляем параметр в getMagazine:
А сам шаблон модифицируем следующим образом:
Слайд 26Pointcut
Вызовем метод в Test1:
Вывод:
![Pointcut Вызовем метод в Test1: Вывод:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-25.jpg)
Слайд 27Pointcut
Если же мы хотим, чтобы под описанный шаблон подходил метод с любым
![Pointcut Если же мы хотим, чтобы под описанный шаблон подходил метод с](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-26.jpg)
количеством параметров, необходимо * заменить на ..
Это будет работать даже в том случае, если параметров 0
Слайд 28Pointcut
execution(public void getBook(String)) - соответствует методу с параметром String, где бы он
![Pointcut execution(public void getBook(String)) - соответствует методу с параметром String, где бы](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-27.jpg)
ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(public void getBook(*)) - соответствует методу с любым одним параметром, где бы он ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(public void getBook(..)) - соответствует методу с любым количеством любого типа параметров, где бы он ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
Слайд 29Pointcut
Рассмотрим ситуацию, когда параметр имеет тип созданного нами класса. Создадим класс Book:
![Pointcut Рассмотрим ситуацию, когда параметр имеет тип созданного нами класса. Создадим класс Book:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-28.jpg)
Слайд 30Pointcut
В UniLibrary меняем параметр метода getBook на Book.
В Test1 получаем объект класса
![Pointcut В UniLibrary меняем параметр метода getBook на Book. В Test1 получаем](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-29.jpg)
Book и передаем в метод getBook.
Слайд 31Pointcut
Но, если в параметре Advice мы напишем просто Book будет ошибка.
Нашему Pointcut
![Pointcut Но, если в параметре Advice мы напишем просто Book будет ошибка.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-30.jpg)
непонятно, о каком типе идет речь. Необходимо указать полное имя класса.
Слайд 32Pointcut
execution(public void getBook(com.donnu.demo.aop.Book, ..)) - соответствует методу с первым параметром Book, и
![Pointcut execution(public void getBook(com.donnu.demo.aop.Book, ..)) - соответствует методу с первым параметром Book,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-31.jpg)
любым количеством других параметров, даже 0, где бы он ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(* *(..)) - соответствует методу с любым количеством других параметров любого типа, где бы он ни находился, с любым модификатором доступа, любым возвращаемым типом и любым названием
Слайд 33Pointcut
Вернем UniLibrary и другие элементы в исходное состояние
![Pointcut Вернем UniLibrary и другие элементы в исходное состояние](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-32.jpg)
Слайд 34Pointcut
Изменим Aspect, чтобы реализовать в нем и Advice для проверки прав.
![Pointcut Изменим Aspect, чтобы реализовать в нем и Advice для проверки прав.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-33.jpg)
Слайд 35Pointcut
Проверим работу Advice.
Логика работы beforeGetSecurityAdvice будет аналогична beforeGetLoggingAdvice:
![Pointcut Проверим работу Advice. Логика работы beforeGetSecurityAdvice будет аналогична beforeGetLoggingAdvice:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-34.jpg)
Слайд 36Pointcut
Для того, чтобы не пользоваться копированием, когда для нескольких Advice подходит один
![Pointcut Для того, чтобы не пользоваться копированием, когда для нескольких Advice подходит](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-35.jpg)
и тот же Pointcut, есть возможность объявить Pointcut, а потом использовать его несколько раз.
@Pointcut(“pointcut_expression”)
private void pointcut_reference(){}
Использование:
@Before(“pointcut_reference()”)
public void advice_name(){ /*code*/}
Слайд 37Pointcut
В нашем примере будет выглядеть следующим образом:
![Pointcut В нашем примере будет выглядеть следующим образом:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-36.jpg)
Слайд 38Pointcut
Если данный метод будет иметь модификатор доступа public, то мы сможем использовать
![Pointcut Если данный метод будет иметь модификатор доступа public, то мы сможем](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-37.jpg)
его в других классах аспектах.
@Pointcut(“pointcut_expression”)
public void pointcut_reference(){}
Слайд 39Pointcut
Плюсы объявления Pointcut:
Возможность использования одного Pointcut для множества Advice
Возможность быстрого изменения Pointcut
![Pointcut Плюсы объявления Pointcut: Возможность использования одного Pointcut для множества Advice Возможность](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-38.jpg)
для множества Advice
Возможность комбинирования Pointcut
Слайд 40Комбинирование Pointcut
Добавим в класс UniLibrary несколько методов
![Комбинирование Pointcut Добавим в класс UniLibrary несколько методов](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-39.jpg)
Слайд 41Комбинирование Pointcut
Добавим в LoggingAndSecurityAspect добавим метод логирования получения книг
![Комбинирование Pointcut Добавим в LoggingAndSecurityAspect добавим метод логирования получения книг](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-40.jpg)
Слайд 42Комбинирование Pointcut
Аналогично для return-методов. Но, что если у нас есть сквозная логика,
![Комбинирование Pointcut Аналогично для return-методов. Но, что если у нас есть сквозная](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-41.jpg)
которая должна выполняться в обоих случаях?
Слайд 43Комбинирование Pointcut
Комбинирование Pointcut-ов – это их объединение с помощью логических операторов &&
![Комбинирование Pointcut Комбинирование Pointcut-ов – это их объединение с помощью логических операторов && || !](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-42.jpg)
|| !
Слайд 45Комбинирование Pointcut
Запустим Test1
![Комбинирование Pointcut Запустим Test1](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-44.jpg)
Слайд 46Комбинирование Pointcut
Рассмотрим ситуацию, когда мы хотим вызвать Advice для всех методов кроме
![Комбинирование Pointcut Рассмотрим ситуацию, когда мы хотим вызвать Advice для всех методов кроме одного.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-45.jpg)
одного.
Слайд 47Комбинирование Pointcut
Вызываем Test1
![Комбинирование Pointcut Вызываем Test1](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-46.jpg)
Слайд 48Порядок выполнения Aspect-ов
Рассмотрим ранее написанный пример.
![Порядок выполнения Aspect-ов Рассмотрим ранее написанный пример.](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-47.jpg)
Слайд 49Порядок выполнения Aspect-ов
В Test1 вызовем методы с get.
Вывод:
![Порядок выполнения Aspect-ов В Test1 вызовем методы с get. Вывод:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-48.jpg)
Слайд 50Порядок выполнения Aspect-ов
Каким образом мы можем контролировать порядок выполнения?
Для этого нам потребуется
![Порядок выполнения Aspect-ов Каким образом мы можем контролировать порядок выполнения? Для этого](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-49.jpg)
вынести методы в разные аспекты. Но начнем с того, что вынесем Pointcut в отдельный класс.
Установим модификатор доступа public, чтобы мы могли к нему обратиться из другого класса.
Слайд 51Порядок выполнения Aspect-ов
Теперь создадим два аспекта. Обратите внимание, что для того, чтобы
![Порядок выполнения Aspect-ов Теперь создадим два аспекта. Обратите внимание, что для того,](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-50.jpg)
получить Pointcut необходимо указать полное имя класса.
Слайд 52Порядок выполнения Aspect-ов
Создадим еще один аспект.
Теперь у нас три аспект-класса и три
![Порядок выполнения Aspect-ов Создадим еще один аспект. Теперь у нас три аспект-класса](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-51.jpg)
Advice направленных на get-метод.
Слайд 53Порядок выполнения Aspect-ов
Теперь мы можем указать им порядок, с помощью аннотации @Order
![Порядок выполнения Aspect-ов Теперь мы можем указать им порядок, с помощью аннотации @Order](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-52.jpg)
Слайд 54Порядок выполнения Aspect-ов
Вывод до аннотации @Order:
Вывод после:
![Порядок выполнения Aspect-ов Вывод до аннотации @Order: Вывод после:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-53.jpg)
Слайд 55Порядок выполнения Aspect-ов
Если при вызове одного метода с бизнес-логикой срабатывает несколько Advice,
![Порядок выполнения Aspect-ов Если при вызове одного метода с бизнес-логикой срабатывает несколько](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/858448/slide-54.jpg)
то нет никакой гарантии, что они выполнятся в желаемом порядке.
Для соблюдении порядка такие Advice необходимо распределить по отдельным, упорядоченным аспектам.
Аннотация @Order(1) упорядочивает аспекты. Чем меньше число, тем выше приоритет. Число должно быть целым, отрицательное допустимо.