Вокруг совета и продолжайте вызов: аспект J, как это работает?

Я пытался понять, в чем around совет работает AspectJ.

Это не так просто, как советы до и после. Может ли кто-нибудь кратко рассказать о том, что делает совет around и какова цель ключевого слова proceed?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
485
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Очень неформально совет around перехватывает заданную точку соединения и может внедрять новое поведение до, после и вместо этой точки соединения. proceed — это специальная функция, которая позволяет around совету продолжать выполнение joinpoint.

Из типов советов, поддерживаемых AspectJ (т. е. before, after и around), совет around является единственным, которому разрешено возвращать значение и/или использовать proceed. Это позволяет совету around выполнять одну и ту же точку соединения несколько раз или вообще не выполнять ее. Кроме того, вы даже можете выполнить перехваченную точку соединения с другим контекстом (например, изменить значение аргументов метода). Подробнее можно узнать здесь.

Давайте использовать код в качестве примера. Представьте себе класс с именем Rectangle:

public class Rectangle {
    private double width, height;

    public void setWidth(double w) {
           System.out.println("Set Width " + w);
           this.width = w;
    }
 
    public void setHeight(double h) {
           System.out.println("Set height " + h);
           this.height = h;
    }

    
    public double getWidth() {return this.width;}
    public double getHeight() {return this.height; }
}

и вызываемые методы этого класса:

public class Main {
    
    public static void main(String[] args) {
        Rectangle s = new Rectangle();
        s.setWidth(10);
        s.setHeight(2);
        double w =  s.getWidth();
        double h = s.getHeight()
        System.out.println("Width " + w + " Height " + h);
    }
}

Если вы запустите приведенный выше код, вы получите следующий вывод:

Set Width 10.0
Set Height 2.0
Width 10.0 Height 2.0

Тем не менее, давайте добавим несколько around советов:

 void around(double w) : call(public void  Rectangle.setWidth(double)) && args(w){
      System.out.println("Before setting width");
      proceed(w + 100);
      proceed(w + 100);
      System.out.println("After setting width");
 }
 
 double around() : call(public double  Rectangle.getHeight()){
        System.out.println("Before getting Height");
        double h = proceed();
        System.out.println("After getting Height");
        return h + 200;
 }

 void around(double w) : call(public void  Rectangle.setHeight(double)) && args(w){
        System.out.println("No Height setting");
  }

Теперь вы получите вывод:

Before setting width
Set Width 110.0
Set Width 110.0
After setting width
No Height setting
Before getting Height
After getting Height
Width 110.0 Height 200.0

Итак, давайте попробуем понять смысл этого вывода, шаг за шагом, не так ли?!. Первый совет перехватит вызов метода public void Rectangle.setWidth(double) в классе Rectangle. И воля:

  1. добавьте оператор System.out.println("Before setting width"); перед вызовом этого метода;
  2. выполнить точку соединения дважды (т. е. дважды вызвать метод setWidth), изменив исходный параметр с w на w + 100;
  3. добавьте оператор System.out.println("After setting width"); после вызова этого метода.

Следовательно, исходный код теперь эквивалентен:

public class Main {
    
    public static void main(String[] args) {
        Rectangle s = new Rectangle();
        System.out.println("Before setting width");  // <--- new lines
        s.setWidth(10+100);
        s.setWidth(10+100);
        System.out.println("After setting width");   // <--- new lines
        s.setHeight(2);
        double w =  s.getWidth();
        double h = s.getHeight()
        System.out.println("Width " + w + " Height " + h);
    }
}

Второй совет around будет перехватывать вызовы метода public double Rectangle.getHeight(), вводить до и после того, как метод вызовет операторы System.out.println("Before getting Height"); и System.out.println("After getting Height"); соответственно. Более того, добавит 200 к значению, возвращаемому getHeight. Следовательно,

public class Main {
    
    public static void main(String[] args) {
        Rectangle s = new Rectangle();
        System.out.println("Before setting width"); 
        s.setWidth(10+100);
        s.setWidth(10+100);
        System.out.println("After setting width");  
        s.setHeight(2);
        double w =  s.getWidth();
        System.out.println("Before getting Height"); // <-- new lines
        double h = s.getHeight() + 200 // <-- new behaviour 
        System.out.println("After getting Height"); // <-- new lines
        System.out.println("Width " + w + " Height " + h); 

    }
}

Наконец, третий around совет заменит вызов метода public void Rectangle.setHeight(double) оператором System.out.println("No Height setting");. Следовательно:

public class Main {
    
    public static void main(String[] args) {
        Rectangle s = new Rectangle();
        System.out.println("Before setting width"); 
        s.setWidth(10+100);
        s.setWidth(10+100);
        System.out.println("After setting width");
        System.out.println("No Height setting"); // <-- new line  
        double w =  s.getWidth();
        System.out.println("Before getting Height");
        double h = s.getHeight() + 200 // <-- new behaviour 
        System.out.println("After getting Height");
        System.out.println("Width " + w + " Height " + h); 

    }
}

Это всего лишь небольшая иллюстрация того, как работает совет around, не означает, что вы должны повторить то же самое, что было сделано в этом примере, и не точно показывает, как происходит процесс плетения под капотом.

Другие вопросы по теме