AspectJ проблемы с использованием вокруг совета и ProceedingJoinPoint - PullRequest
0 голосов
/ 22 ноября 2018

Я новичок в AOP и мне нужно использовать AspectJ в моем проекте.Мне нужно использовать советы, но у меня возникли проблемы с их использованием, в моем классе .aj есть следующий код,

pointcut checkUser(ProceedingJoinPoint jp,User user): call(* com.example.UserAccount.MyUI.checkUser(..))&& args(jp,user);

void around(ProceedingJoinPoint jp,User user) throws Throwable : checkUser(jp,user){
    // Condition checks one of the user boolean property
    if(condition){
        jp.proceed();
    }else{
        // Do nothing
    }   
}

, но я получаю это предупреждение постоянно,

advice defined in Aspects.UserAccount has not been applied [Xlint:adviceDidNotMatch]

Кстати, я попробовал это без ProceedingJoinPoint и попробовал просто proceed();, но затем получил это предупреждение, too few arguments to proceed, expected 1

Я благодарен за любую помощь или подсказку!

Рез

1 Ответ

0 голосов
/ 25 ноября 2018

Сначала я рекомендую прочитать документацию AspectJ, чтобы узнать синтаксис.Поскольку вы используете собственный синтаксис AspectJ, это похоже на изучение нового языка программирования или, по крайней мере, расширения Java.Что вы делаете, это смешивает собственный синтаксис с синтаксисом на основе аннотаций.Попробуйте придерживаться одного.Я уверен, что вы не нашли этого ни в одном учебном пособии, но в итоге использовали этот синтаксис методом проб и ошибок.

Вам не нужно связывать параметр точки соединения в собственном синтаксисе, поскольку он существует неявно и автоматически.Автоматически связанная точка соединения всегда называется thisJoinPoint, что наверняка покажет все уроки.Только в синтаксисе, основанном на аннотациях, вам нужно связать точку соединения и назвать ее по своему желанию, но даже тогда я рекомендую придерживаться thisJoinPoint, потому что тогда рефакторинг от аннотации к собственному синтаксису будет проще, и ваши глаза привыкнут определять эту переменнуюname в вашем коде аспекта.

Полученное предупреждение означает, что определенный вами pointcut не соответствует ни одной части вашего кода, по крайней мере, ни одной части, которая видна ткачу или компилятору аспектов.Может быть множество причин, по которым это может происходить, например, имена пакетов или классов с ошибками, неправильные в отношении типа возврата совета (тип возврата должен быть Object для не пустых методов или более точно совпадать с тем, что возвращает метод, который вы хотите перехватить).Предполагая, что, например, checkUser(..) возвращает boolean, совет по окружению должен делать то же самое.Я составил пример, используя ваши имена пакетов и классов.Кроме того, имена пакетов должны быть в нижнем регистре, но я использовал ваши, предполагая, что это действительно имена пакетов, а не внутренние классы:

Вспомогательный класс:

package com.example.UserAccount;

public class User {
  private String name;

  public User(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public String toString() {
    return "User(" + name + ")";
  }
}

Класс, на который ориентирован аспект + пример основного метода:

package com.example.UserAccount;

public class MyUI {
  public boolean checkUser(User user) {
    return user.getName().toUpperCase().contains("ADMIN");
  }

  public static void main(String[] args) {
    MyUI ui = new MyUI();
    System.out.println(ui.checkUser(new User("Administrator")));
    System.out.println(ui.checkUser(new User("john")));
    System.out.println(ui.checkUser(new User("xander")));
    System.out.println(ui.checkUser(new User("admiral")));
    System.out.println(ui.checkUser(new User("SySaDmiN")));
  }
}

Как вы можете видеть, мы ожидаем вывод «true» для первой и последней записи, но «false» для нихмежду ними из-за логики проверки, которую я составил для checkUser(..).

Теперь давайте напишем аспект, который также возвращает «true» для пользователя с именем «Xander», например, чтобы дать ему права администратора илибез разницы.Я придумываю это, потому что вы не предоставили MCVE , как вы всегда должны в StackOverflow, а просто фрагмент кода, который заставляет всех пытаться ответить на ваш вопрос, угадывая, какого чёрта вы хотите достичь и какчтобы воспроизвести вашу проблему.

Формат:

package Aspects;

import com.example.UserAccount.User;
import com.example.UserAccount.MyUI;

public aspect UserAccount {
  pointcut checkUser(User user) :
    execution(boolean MyUI.checkUser(*)) && args(user);

  boolean around(User user) : checkUser(user) {
    System.out.println(thisJoinPoint + " -> " + user);
    if (user.getName().equalsIgnoreCase("xander"))
      return true;
    return proceed(user);
  }
}

Я только что импортировал класс MyUI, поэтому нет необходимости использовать полное имя классаВот.Опять же, это преимущество нативного синтаксиса, в синтаксисе на основе аннотаций вам придется использовать полное имя.

Я также заменил универсальный * MyUI.checkUser(..) (который также будет работать) на более явный boolean MyUI.checkUser(*), потому что мы уже знаем, что метод возвращает логическое значение и имеет ровно один параметр, который мы в любом случае предполагаем, возвращая логическое значение из совета вокруг и связывая ровно один параметр через args().Вы также можете быть еще более конкретным и использовать boolean MyUI.checkUser(User).

Более того, я использую execution() вместо call(), потому что это более эффективно, так как он однажды вплетает код рекомендации только в метод выполнениявместо пяти раз для каждого вызова метода в основном методе.Вам нужно использовать call(), только если класс MyUI находится вне досягаемости ткача / компилятора AspectJ, т. Е. Потому что его нет в модуле, который вы компилируете с AspectJ Maven.

Журнал консоли:

execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(Administrator)
true
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(john)
false
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(xander)
true
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(admiral)
false
execution(boolean com.example.UserAccount.MyUI.checkUser(User)) -> User(SySaDmiN)
true

Et voilà, аспект работает.Это заставляет целевой метод возвращать "true" для пользователя "xander".

...