вокруг совета и продолжайте звонить: AspectJ, как это работает?

#java #aop #aspectj

#java #aop #aspectj

Вопрос:

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

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

Ответ №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)) amp;amp; 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)) amp;amp; 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 , не означает, что вы должны повторить то же самое, что было сделано в этом примере, и не точно показывает, как процесс плетения происходит под капотом.