Объектно-ориентированное программирование. Лекция 4

Содержание

Слайд 2

План

Pointcut
Комбинирование Pointcut
Порядок выполнения Aspect-ов

План Pointcut Комбинирование Pointcut Порядок выполнения Aspect-ов

Слайд 3

Pointcut

Pointcut – выражение, описывающее, где должен быть применен Advice.
Spring AOP использует AspectJ

Pointcut Pointcut – выражение, описывающее, где должен быть применен Advice. Spring AOP
Pointcut expression language, то есть определенные правила в написании выражений для создания Pointcut.

Слайд 4

Pointcut

Для описания Pointcut используется шаблон. Выделены обязательные элементы.
execution( modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(parameters-pattern)

Pointcut Для описания Pointcut используется шаблон. Выделены обязательные элементы. execution( modifiers-pattern? return-type-pattern
throws-pattern? )
Под шаблон может подходить один или несколько методов, в зависимости от того, насколько детально был описан шаблон.

Слайд 5

Pointcut

Рассмотрим пример с предыдущей лекции.
По шаблону мы указали все, кроме declaring-type-pattern и

Pointcut Рассмотрим пример с предыдущей лекции. По шаблону мы указали все, кроме
throws-pattern. Отсутствие declaring-type-pattern означает, что под шаблон подойдет метод getBook() абсолютно любого класса.

Слайд 6

Pointcut

Создадим абстрактный класс
от которого будет наследоваться класс Library

Pointcut Создадим абстрактный класс от которого будет наследоваться класс Library

Слайд 7

Pointcut

Переименуем класс, чтобы его название конкретизировало его природу. Например, в университетскую библиотеку.
Создадим

Pointcut Переименуем класс, чтобы его название конкретизировало его природу. Например, в университетскую
класс школьная библиотека.
Как вы можете видеть, под шаблон подходит оба метода.

Слайд 8

Pointcut

Вызовем метод в классе Test1

Pointcut Вызовем метод в классе Test1

Слайд 9

Pointcut

Вывод:
Это произошло, поскольку оба метода подходят под Pointcut.

Pointcut Вывод: Это произошло, поскольку оба метода подходят под Pointcut.

Слайд 10

Pointcut

Модифицируем Pointcut, чтобы метод вызвался только для UniLibrary. Для этого нам необходимо

Pointcut Модифицируем Pointcut, чтобы метод вызвался только для UniLibrary. Для этого нам
указать declaring-type-pattern, а именно полное имя класса UniLibrary.
Вывод:

Слайд 11

Pointcut

execution(public void getBook()) – соответствует методу без параметров, где бы он ни

Pointcut execution(public void getBook()) – соответствует методу без параметров, где бы он
находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(public void com.donnu.demo.aop.UniLibrary.getBook()) – соответствует методу без параметров, из класса UniLibrary, с модификатором доступа public, возвращаемым типом void и названием getBook()

Слайд 12

Pointcut

execution(public void get*()) – соответствует методу без параметров, где бы он ни

Pointcut execution(public void get*()) – соответствует методу без параметров, где бы он
находился, с модификатором доступа public, возвращаемым типом void и названием, начинающимся на get.

Слайд 13

Pointcut

Добавим метод getMagazine в UniLibrary.

Pointcut Добавим метод getMagazine в UniLibrary.

Слайд 14

Pointcut

Добавим вызов метода getMagazine в Test1.

Pointcut Добавим вызов метода getMagazine в Test1.

Слайд 15

Pointcut

Как мы можем видеть аспект был вызван трижды. Для getBook и getMagazine

Pointcut Как мы можем видеть аспект был вызван трижды. Для getBook и
из UniLibrary и getBook из SchoolLibrary. Все эти методы подошли под шаблон.

Слайд 16

Pointcut

Приведем пример работы с return-type-pattern. Добавим еще один Advice:
и метод в UniLibrary:

Pointcut Приведем пример работы с return-type-pattern. Добавим еще один Advice: и метод в UniLibrary:

Слайд 17

Pointcut

В классе Test1 вызовем метод returnBook:
Вывод указывает на то, что Advice работает:

Pointcut В классе Test1 вызовем метод returnBook: Вывод указывает на то, что Advice работает:

Слайд 18

Pointcut

Теперь, если мы изменим возвращаемый тип, например вот так:
Метод больше не будет

Pointcut Теперь, если мы изменим возвращаемый тип, например вот так: Метод больше
подходить под шаблон, Advice не будет вызван. Если же мы не хотим зависеть от возвращаемого типа, а он является обязательным параметром шаблона, мы можем изменить возвращаемый тип на *:

Слайд 19

Pointcut

Если мы хотим аналогичным образом поступить с модификатором доступа, мы можем просто

Pointcut Если мы хотим аналогичным образом поступить с модификатором доступа, мы можем
его убрать, оставив только *.
Как вы помните modifiers-pattern не является обязательным элементом шаблона.

Слайд 20

Pointcut

Таким образом:
execution(* returnBook()) - соответствует методу без параметров, где бы он ни

Pointcut Таким образом: execution(* returnBook()) - соответствует методу без параметров, где бы
находился, с любым модификатором доступа, любым возвращаемым типом и названием returnBook()
execution(* *()) - соответствует методу без параметров, где бы он ни находился, с любым модификатором доступа, любым возвращаемым типом и любым называнием

Слайд 21

Pointcut

Рассмотрим параметры метода при написании Pointcut. Для этого вернем класс UniLibrary в

Pointcut Рассмотрим параметры метода при написании Pointcut. Для этого вернем класс UniLibrary
первоначальное состояние.
Это необходимо для более простой работы с добавлением параметров.

Слайд 22

Pointcut

Добавим параметр в метод getBook
В Test1 добавим параметр при вызове метода
Убедимся, что

Pointcut Добавим параметр в метод getBook В Test1 добавим параметр при вызове
при этом наш Advice больше не срабатывает

Слайд 23

Pointcut

Добавим параметр в Advice. Обратите внимание, что указывается только тип параметра, но

Pointcut Добавим параметр в Advice. Обратите внимание, что указывается только тип параметра,
не его название.
Вывод:

Слайд 24

Pointcut

execution(public void getBook(String)) - соответствует методу с параметром String, где бы он

Pointcut execution(public void getBook(String)) - соответствует методу с параметром String, где бы
ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()

Слайд 25

Pointcut

Допустим, что мы хотим, чтобы под наш шаблон подходил любой метод, имеющий

Pointcut Допустим, что мы хотим, чтобы под наш шаблон подходил любой метод,
только 1 параметр. Для этого добавляем параметр в getMagazine:
А сам шаблон модифицируем следующим образом:

Слайд 26

Pointcut

Вызовем метод в Test1:
Вывод:

Pointcut Вызовем метод в Test1: Вывод:

Слайд 27

Pointcut

Если же мы хотим, чтобы под описанный шаблон подходил метод с любым

Pointcut Если же мы хотим, чтобы под описанный шаблон подходил метод с
количеством параметров, необходимо * заменить на ..
Это будет работать даже в том случае, если параметров 0

Слайд 28

Pointcut

execution(public void getBook(String)) - соответствует методу с параметром String, где бы он

Pointcut execution(public void getBook(String)) - соответствует методу с параметром String, где бы
ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(public void getBook(*)) - соответствует методу с любым одним параметром, где бы он ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(public void getBook(..)) - соответствует методу с любым количеством любого типа параметров, где бы он ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()

Слайд 29

Pointcut

Рассмотрим ситуацию, когда параметр имеет тип созданного нами класса. Создадим класс Book:

Pointcut Рассмотрим ситуацию, когда параметр имеет тип созданного нами класса. Создадим класс Book:

Слайд 30

Pointcut

В UniLibrary меняем параметр метода getBook на Book.
В Test1 получаем объект класса

Pointcut В UniLibrary меняем параметр метода getBook на Book. В Test1 получаем
Book и передаем в метод getBook.

Слайд 31

Pointcut

Но, если в параметре Advice мы напишем просто Book будет ошибка.
Нашему Pointcut

Pointcut Но, если в параметре Advice мы напишем просто Book будет ошибка.
непонятно, о каком типе идет речь. Необходимо указать полное имя класса.

Слайд 32

Pointcut

execution(public void getBook(com.donnu.demo.aop.Book, ..)) - соответствует методу с первым параметром Book, и

Pointcut execution(public void getBook(com.donnu.demo.aop.Book, ..)) - соответствует методу с первым параметром Book,
любым количеством других параметров, даже 0, где бы он ни находился, с модификатором доступа public, возвращаемым типом void и названием getBook()
execution(* *(..)) - соответствует методу с любым количеством других параметров любого типа, где бы он ни находился, с любым модификатором доступа, любым возвращаемым типом и любым названием

Слайд 33

Pointcut

Вернем UniLibrary и другие элементы в исходное состояние

Pointcut Вернем UniLibrary и другие элементы в исходное состояние

Слайд 34

Pointcut

Изменим Aspect, чтобы реализовать в нем и Advice для проверки прав.

Pointcut Изменим Aspect, чтобы реализовать в нем и Advice для проверки прав.

Слайд 35

Pointcut

Проверим работу Advice.
Логика работы beforeGetSecurityAdvice будет аналогична beforeGetLoggingAdvice:

Pointcut Проверим работу Advice. Логика работы beforeGetSecurityAdvice будет аналогична beforeGetLoggingAdvice:

Слайд 36

Pointcut

Для того, чтобы не пользоваться копированием, когда для нескольких Advice подходит один

Pointcut Для того, чтобы не пользоваться копированием, когда для нескольких Advice подходит
и тот же Pointcut, есть возможность объявить Pointcut, а потом использовать его несколько раз.
@Pointcut(“pointcut_expression”)
private void pointcut_reference(){}
Использование:
@Before(“pointcut_reference()”)
public void advice_name(){ /*code*/}

Слайд 37

Pointcut

В нашем примере будет выглядеть следующим образом:

Pointcut В нашем примере будет выглядеть следующим образом:

Слайд 38

Pointcut

Если данный метод будет иметь модификатор доступа public, то мы сможем использовать

Pointcut Если данный метод будет иметь модификатор доступа public, то мы сможем
его в других классах аспектах.
@Pointcut(“pointcut_expression”)
public void pointcut_reference(){}

Слайд 39

Pointcut

Плюсы объявления Pointcut:
Возможность использования одного Pointcut для множества Advice
Возможность быстрого изменения Pointcut

Pointcut Плюсы объявления Pointcut: Возможность использования одного Pointcut для множества Advice Возможность
для множества Advice
Возможность комбинирования Pointcut

Слайд 40

Комбинирование Pointcut

Добавим в класс UniLibrary несколько методов

Комбинирование Pointcut Добавим в класс UniLibrary несколько методов

Слайд 41

Комбинирование Pointcut

Добавим в LoggingAndSecurityAspect добавим метод логирования получения книг

Комбинирование Pointcut Добавим в LoggingAndSecurityAspect добавим метод логирования получения книг

Слайд 42

Комбинирование Pointcut

Аналогично для return-методов. Но, что если у нас есть сквозная логика,

Комбинирование Pointcut Аналогично для return-методов. Но, что если у нас есть сквозная
которая должна выполняться в обоих случаях?

Слайд 43

Комбинирование Pointcut

Комбинирование Pointcut-ов – это их объединение с помощью логических операторов &&

Комбинирование Pointcut Комбинирование Pointcut-ов – это их объединение с помощью логических операторов && || !
|| !

Слайд 44

Комбинирование Pointcut

Комбинирование Pointcut

Слайд 45

Комбинирование Pointcut

Запустим Test1

Комбинирование Pointcut Запустим Test1

Слайд 46

Комбинирование Pointcut

Рассмотрим ситуацию, когда мы хотим вызвать Advice для всех методов кроме

Комбинирование Pointcut Рассмотрим ситуацию, когда мы хотим вызвать Advice для всех методов кроме одного.
одного.

Слайд 47

Комбинирование Pointcut

Вызываем Test1

Комбинирование Pointcut Вызываем Test1

Слайд 48

Порядок выполнения Aspect-ов

Рассмотрим ранее написанный пример.

Порядок выполнения Aspect-ов Рассмотрим ранее написанный пример.

Слайд 49

Порядок выполнения Aspect-ов

В Test1 вызовем методы с get.
Вывод:

Порядок выполнения Aspect-ов В Test1 вызовем методы с get. Вывод:

Слайд 50

Порядок выполнения Aspect-ов

Каким образом мы можем контролировать порядок выполнения?
Для этого нам потребуется

Порядок выполнения Aspect-ов Каким образом мы можем контролировать порядок выполнения? Для этого
вынести методы в разные аспекты. Но начнем с того, что вынесем Pointcut в отдельный класс.
Установим модификатор доступа public, чтобы мы могли к нему обратиться из другого класса.

Слайд 51

Порядок выполнения Aspect-ов

Теперь создадим два аспекта. Обратите внимание, что для того, чтобы

Порядок выполнения Aspect-ов Теперь создадим два аспекта. Обратите внимание, что для того,
получить Pointcut необходимо указать полное имя класса.

Слайд 52

Порядок выполнения Aspect-ов

Создадим еще один аспект.
Теперь у нас три аспект-класса и три

Порядок выполнения Aspect-ов Создадим еще один аспект. Теперь у нас три аспект-класса
Advice направленных на get-метод.

Слайд 53

Порядок выполнения Aspect-ов

Теперь мы можем указать им порядок, с помощью аннотации @Order

Порядок выполнения Aspect-ов Теперь мы можем указать им порядок, с помощью аннотации @Order

Слайд 54

Порядок выполнения Aspect-ов

Вывод до аннотации @Order:
Вывод после:

Порядок выполнения Aspect-ов Вывод до аннотации @Order: Вывод после:

Слайд 55

Порядок выполнения Aspect-ов

Если при вызове одного метода с бизнес-логикой срабатывает несколько Advice,

Порядок выполнения Aspect-ов Если при вызове одного метода с бизнес-логикой срабатывает несколько
то нет никакой гарантии, что они выполнятся в желаемом порядке.
Для соблюдении порядка такие Advice необходимо распределить по отдельным, упорядоченным аспектам.
Аннотация @Order(1) упорядочивает аспекты. Чем меньше число, тем выше приоритет. Число должно быть целым, отрицательное допустимо.