问题
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:
- add the statement
System.out.println("Before setting width");
before the call of that method; - execute the joinpoint twice (i.e., call the method
setWidth
twice), modifying its original parameter fromw
tow + 100
; - 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