【问题标题】:around advice and proceed call: aspectJ, how it works?围绕建议和进行呼叫:aspectJ,它是如何工作的?
【发布时间】:2020-12-11 15:24:09
【问题描述】:

我一直试图弄清楚around 建议AspectJ 中的作用。

这不像之前和之后建议那样简单。有人可以简要介绍一下around 建议的作用以及proceed 关键字的用途吗?

【问题讨论】:

    标签: java aop aspectj


    【解决方案1】:

    非常非正式地,aroundadvice 拦截给定的joinpoint,并且可以注入新的行为之前 , after, 而不是那个joinpointproceed 是一个特殊的功能,它允许around 建议继续执行joinpoint

    根据 AspectJ 支持的 advice 类型( beforeafteraround),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) 的调用。并且会:

    1. 在调用该方法之前添加语句System.out.println("Before setting width");
    2. 执行joinpoint两次(调用方法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 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 工作原理的一个小说明,并不意味着您应该复制在此示例中所做的相同操作,也不能准确显示 编织过程发生在幕后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多