Чтение и понимание точек AspectJ?

/* 0 */ pointcut services(Server s): target(s) && call(public * *(..))

Этот pointcut, названный services, выбирает те точки в выполнении программы, когда у объектов сервера вызываются их общедоступные методы. Это также позволяет любому, кто использует pointcut служб, получить доступ к объекту сервера, чей метод вызывается. (взято из https://eclipse.org/aspectj/doc/released/progguide/language-anatomy.html)

Я пытаюсь понять точечные сокращения AspectJ и сейчас немного запутался. Мой главный вопрос: как вы читаете приведенный выше pointcut и как вы «разгадываете» его смысл вместе?

Чтобы проиллюстрировать мое замешательство, давайте попробуем построить все с нуля:

Следующий pointcut перехватит все вызовы общедоступных методов для любого объекта, верно?

/* 1 */ pointcut services() : call(public * *(..))

Теперь, что насчет этого:

/* 2 */ pointcut services() : call(public * Server.*(..)) 

Я предполагаю, что это будет перехватывать любые точки при вызове общедоступных методов объекта Server.

Теперь, как мне перейти отсюда к начальному примеру 0? И как я это читаю?

Не могли бы вы сначала предоставить список параметров при построении pointcut?

/* 3a */ pointcut services(Server s) : call(public * *(..))

Это то же самое, что и номер 2 выше? (У меня есть ощущение, что это не сработает, а если и сработает, то будет «перехватывать» каждый вызов общедоступного метода, как и в случае с номером 1.) Во всяком случае, будет ли следующее то же самое? (Я еще не «захватываю» s с помощью собственного pointcut, поэтому я не могу его точно определить, не так ли?)

/* 4a */ pointcut services(Server /* only type, no variable */) : call(public * *(..))

Или вы бы начали с указания собственного pointcut, чтобы «захватить» целевой объект, например так:

/* 3b */ pointcut services() : target(s) && call(public * *(..))

Я полагаю, что все равно будет перехватывать все вызовы общедоступных методов для любого объекта?

Будет ли следующее работать только для перехвата вызовов объекта «Сервер» и «захвата» этого объекта (без предоставления его для последующей передачи, например, для совета)?

/* 5 */ pointcut services(/*nothing here*/) : target(s) && call(public * Server.*(..))

Теперь вернемся к исходному pointcut:

/* 0 */ pointcut services(Server s): target(s) && call(public * *(..))

Это то же самое, что

/* 6 */ pointcut services(Server s): target(s) && call(public * Server.*(..))

Итак, подведем итог: как начать расшифровку 0?

Вы сначала смотрите на target pointcut, затем на тип параметра services pointcut и читаете его "наизнанку"/"справа налево"? Или вы сначала смотрите список параметров, а затем смотрите в pointcut services, чтобы увидеть, откуда взялся аргумент (т.е. target(s))?

Или я слишком все усложняю? Я где-то упустил важный момент, чтобы помочь мне понять это?

Редактировать: руководство объясняет это слева направо, но откуда берется аргумент для параметра Server s, если я еще не "выполнил" target(s)?


person Christian    schedule 10.03.2015    source источник
comment
Я думаю, что ответ может быть таким: читать слева направо, выполнять справа налево...   -  person Christian    schedule 10.03.2015


Ответы (1)


1: Да, он перехватывает любой вызов общедоступного метода.

2: он перехватывает любой общедоступный вызов метода для объекта, объявленного как Server, тогда как 0 перехватывает любой общедоступный вызов для объекта, который является экземпляром Server. См. семантику.

3a: Поскольку s не привязан, он не компилируется:

[ERROR] formal unbound in pointcut
        .../src/main/aspect/MyAspect.aj:18
pointcut services(Server s): call(public * *(..));

4a: Синтаксис недействителен, точно так же, как вам нужно называть параметры при объявлении методов в интерфейсе:

[ERROR] Syntax error, insert "... VariableDeclaratorId" to complete FormalParameterList
        .../src/main/aspect/MyAspect.aj:18
pointcut services(Server): call(public * *(..));
                  ^

3b: Это тоже неверно, s не было объявлено:

[WARNING] no match for this type name: s [Xlint:invalidAbsoluteTypeName]
        .../src/main/aspect/MyAspect.aj:18
pointcut services(): target(s) && call(public * *(..));

5: Как и 3b, s не было объявлено.

6: это не то же самое, что 0, это только сопоставляет общедоступные вызовы метода Server (т. е. объявленные в Server) экземпляру Server.

Я проиллюстрировал различные случаи в репозитории Github: переключайтесь между ветками, чтобы попробовать их. В ветке аспект7 есть дополнительный случай, основанный на 6, где я переопределяю hashCode() в Server.

Вы можете (и должны) попробовать сами, чтобы лучше понять.


Чтобы ответить на ваш последний вопрос, аргумент pointcut исходит из того факта, что мы хотим (иметь возможность) получить доступ к цели вызова в совете, указав его в качестве параметра совета. Сигнатура рекомендации должна содержать параметры для всех упомянутых pointcut, а параметры pointcut должны ссылаться на параметры в рекомендации.

Итак, чтобы в совете был параметр Server, он нужен мне в pointcut, и он должен быть привязан к чему-то в определении pointcut.

person Frank Pavageau    schedule 11.03.2015