【发布时间】:2020-12-11 15:24:09
【问题描述】:
我一直试图弄清楚around 建议 在AspectJ 中的作用。
这不像之前和之后建议那样简单。有人可以简要介绍一下around 建议的作用以及proceed 关键字的用途吗?
【问题讨论】:
我一直试图弄清楚around 建议 在AspectJ 中的作用。
这不像之前和之后建议那样简单。有人可以简要介绍一下around 建议的作用以及proceed 关键字的用途吗?
【问题讨论】:
非常非正式地,aroundadvice 拦截给定的joinpoint,并且可以注入新的行为之前 , after, 而不是那个joinpoint。 proceed 是一个特殊的功能,它允许around 建议继续执行joinpoint。
根据 AspectJ 支持的 advice 类型(即 before、after 和 around),aroundadvice 是唯一允许返回 值和/或使用proceed 的方法。这使得around advice 可以多次执行相同的joinpoint,或者根本不执行它。此外,您甚至可以使用不同的上下文执行截获的 joinpoint(例如,更改方法参数的值)。更多详情请见here。
让我们以一些代码为例。想象一个名为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
那么让我们一步一步地尝试理解该输出,好吗?!。第一个advice 将拦截对Rectangle 类中方法public void Rectangle.setWidth(double) 的调用。并且会:
System.out.println("Before setting width");;setWidth两次),将原来的参数w修改为w + 100;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 advice 将拦截对方法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 advice 将替换对方法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);
}
}
这只是 advice around 工作原理的一个小说明,并不意味着您应该复制在此示例中所做的相同操作,也不能准确显示 编织过程发生在幕后。
【讨论】: