around advice and proceed call: aspectJ, how it works?

南笙酒味 提交于 2021-02-10 10:55:15

问题


I've been trying to figure out what the around advice works in AspectJ.

It's not simple like the before and after advice. Could someone please give a brief introductory view of what the around advice does, and what is the purpose of the proceed keyword?


回答1:


Very informally, an around advice intercepts a given joinpoint, and can inject new behavior before, after, and instead of that joinpoint. The proceed is a special feature that allows the around advice to continue the execution of the joinpoint.

From the types of advice supported by AspectJ (i.e., before, after, and around), the around advice is the only one allowed to return a value and/or use the proceed. This makes it possible for an around advice to execute several times the same joinpoint, or not executed it at all. Furthermore, you can even execute the intercepted joinpoint with a different context (e.g., change the value of the method arguments). More details can be found here.

Let us use some code as an example. Imagine a class named 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; }
}

and the methods of that class being called in:

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);
    }
}

If you run the code above, you will get the following output:

Set Width 10.0
Set Height 2.0
Width 10.0 Height 2.0

However, let us add some around advices into the mix:

 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");
  }

Now you will get the output:

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

So let us try to make sense out of that output, step-by-step, shall we?!. The first advice will intercept the call to the method public void Rectangle.setWidth(double) in the class Rectangle. And will:

  1. add the statement System.out.println("Before setting width"); before the call of that method;
  2. execute the joinpoint twice (i.e., call the method setWidth twice), modifying its original parameter from w to w + 100;
  3. add the statement System.out.println("After setting width"); after the call of that method.

Consequently, the original code is now equivalent to:

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);
    }
}

The second around advice will intercept the calls to the method public double Rectangle.getHeight(), inject before and after those method calls the statements System.out.println("Before getting Height"); and System.out.println("After getting Height");, respectively. Moreover, will add 200 to the value returned by getHeight. Hence,

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); 

    }
}

Finally, the third around advice will replace the call to the method public void Rectangle.setHeight(double) by the statement System.out.println("No Height setting");. Consequently:

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); 

    }
}

This is just a small illustration of how the advice around works, does not mean that you should replicate the same what was done in this example, and does not accurately show how the weaving process happens under the hood.



来源:https://stackoverflow.com/questions/65254073/around-advice-and-proceed-call-aspectj-how-it-works

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!