AspectJ 形式在切点中未绑定

AspectJ formal unbound in cutpoint

我有以下 类:

public class Population {
    private int population;

    public Population()
    {
        population = 0;
    }

    public void newYear()
    {
        population += 10;
    }

    public int getPopulation() {
        return population;
    }
}

及以下方面

public aspect StatisticsAspect {

    private static int year = 0;

    pointcut operation(Population caller) : call(* Population.newYear());

    after(Population caller) : operation(caller)
    {
        System.out.println("New Year: " + year);
        year++;

        System.out.println("Population: " + caller.getPopulation());
    } 
}

现在我希望每次调用 newYear() 时,都将 "statistics" 打印到控制台。 不幸的是,我收到 ajc: formal unbound in pointcut 错误。

我需要更改什么才能使其正常工作?

我稍微重构了您的代码,因为 getPopulation() 是一个糟糕的名称并且违反了惯例。顾名思义,返回的不是人口对象,而是人口规模。

至于你的方面,命名caller也不好,因为对象不是调用者,而是被调用者或调用的目标。我只是将参数重命名为 population 因为这次它真的包含了一个人口对象。然后我将它绑定到 target() 参数以使您的错误消息消失。

我还从 call() 切换到 execution() 切入点,因为将代码编织到执行的方法而不是调用方法的每个地方更有效。

我还确保在第一个新年结束并且人口增长后计数从 1 开始,而不是 0。我通过使用 ++size 而不是 size++ 来做到这一点,即 pre- 而不是 post-increment.

现在代码如下所示:

package de.scrum_master.app;

public class Population {
  private int size;

  public Population() {
    size = 0;
  }

  public void newYear() {
    size += 10;
  }

  public int getSize() {
    return size;
  }

  public static void main(String[] args) {
    Population population1 = new Population();
    population1.newYear();
    population1.newYear();
    Population population2 = new Population();
    population2.newYear();
    population2.newYear();
  }
}
package de.scrum_master.aspect;

import de.scrum_master.app.Population;

public aspect StatisticsAspect {
  private static int year = 0;

  pointcut operation(Population population) :
    execution(* Population.newYear()) && target(population);

  after(Population population) : operation(population) {
    System.out.printf("Population for year %d = %d%n", ++year, population.getSize());
  }
}

现在查看控制台日志:

Population for year 1 = 10
Population for year 2 = 20
Population for year 3 = 10
Population for year 4 = 20

你能发现问题吗?您有一个总体年份计数器,但有多个人口。实际上,为了获得正确的统计数据,您应该为每个人口设置一年的计数器。这可以通过每个目标(即每个人口)使用一个方面实例而不是单一方面来完成,当然不再使年份计数器静态:

package de.scrum_master.aspect;

import de.scrum_master.app.Population;

public aspect StatisticsAspect pertarget(execution(Population.new(..))) {
  private int year = 0;

  pointcut operation(Population population) :
    execution(* Population.newYear()) && target(population);

  after(Population population) : operation(population) {
    System.out.printf("%s size for year %d = %d%n", population, ++year, population.getSize());
  }
}

这里,pertarget(execution(Population.new(..))) 的意思是:每个 Population 构造函数执行创建一个方面实例,即每个创建的对象。

现在统计数据是正确的(我还稍微更改了日志消息以打印对象 ID,以便我们可以看到哪个消息属于哪个群体):

de.scrum_master.app.Population@1d44bcfa size for year 1 = 10
de.scrum_master.app.Population@1d44bcfa size for year 2 = 20
de.scrum_master.app.Population@266474c2 size for year 1 = 10
de.scrum_master.app.Population@266474c2 size for year 2 = 20