【问题标题】:AspectJ aspect is not applied in LTW scenarioLTW 场景中未应用 AspectJ 方面
【发布时间】:2015-08-22 15:29:06
【问题描述】:

我正在尝试在独立应用程序中使用 AspectJ,但似乎不起作用。

这是我创建的类-

package oata.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AspectJTest {


    @Around("execution(* *..*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("around fired");
        jp.proceed();
    }
}
package oata;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface AspectTest {
}
package oata;

import oata.AspectTest;

public class TestAspect {
    public void doItWithout(int i) {
        double s = Math.acos(i);
    }

    @AspectTest
    public void doItAnnotated(int i) {
        double s = Math.acos(i);
    }

    public void doItAspect(int i) {
        double s = Math.acos(i);

    }
}
package oata;

import java.util.Date;

public class Test {
    public Test() {
    }

    public static void main(String arg[]) {
        // performance testing
        // invoke method without aspect
        long t1 = new Date().getTime();
        for (int i = 0; i < 1; i++) {
            new TestAspect().doItWithout(i);
        }
        System.out.println("Invoke without aspect:"
                + (new Date().getTime() - t1));
        // invoke method with annotated aspect
        t1 = new Date().getTime();
        for (int i = 0; i < 1; i++) {
            new TestAspect().doItAnnotated(i);
        }
        System.out.println("Invoke annotated aspect method:"
                + (new Date().getTime() - t1));
        // invoke method with aspect but not annotated
        t1 = new Date().getTime();
        for (int i = 0; i < 1; i++) {
            new TestAspect().doItAspect(i);
        }
        System.out.println("Invoke aspect method:"
                + (new Date().getTime() - t1));
    }
}

我还在 src/META_INF 文件夹下创建了 aop.xml 文件

<aspectj>
    <aspects>
        <aspect name="oata.aspect.AspectJTest" />
    </aspects>
    <weaver>
        <include within="oata.*" />
    </weaver>
</aspectj>

然后从命令行,当我尝试使用以下命令运行 Test.java 时,建议中的 System.out.println 不会被打印-

\TestAspectJ\bin>java -javaagent:D:\Project\workspaces\RCS_3.2.1\TestAspectJ\src\aspectjweaver-1.6.10.jar oata.Test

谁能告诉我我做错了什么。

谢谢 AA

【问题讨论】:

  • 我已经改变了主题以反映您的要求。具体来说,我删除了“在非 Spring 应用程序中”部分,因为无论如何 AspectJ 完全独立于 Spring,无需提及。在 Spring 中使用它作为 Spring AOP 的补充或替代是一种特殊情况,而不是正常情况。

标签: java aspectj load-time-weaving


【解决方案1】:

几件事:

  • 您的 META-INF/* 文件夹是否肯定被复制到您运行应用程序的 bin 文件夹中?
  • 您正在指定 oata.* 的包含,它将仅包含 oata 包中的直接类,如果您想要更多的子包(我认为您需要),您需要 oata..*
  • 您是否尝试过指定weaver options="-verbose" - 这对您有什么影响吗?如果它没有显示任何内容,则找不到 aop.xml 文件。如果它确实向您显示了某些内容,它将告诉您正在打开哪些方面。也许然后用-debug 对其进行扩充,以了解更多关于正在发生的事情。
  • 我可能会在您的切入点中包含 !within(AspectJTest) 投诉,否则您可能会在开始工作时自我建议并因堆栈溢出而失败。
  • 最后,我知道您现在没有使用它,但如果您打算使用该注释与 AspectJ 匹配,您需要将其从 SOURCE 保留更改,因为 AspectJ 在字节码级别工作并且不会看到如果它有源保留。

【讨论】:

    【解决方案2】:

    安迪所说的一切都是正确的。因为您似乎是 AspectJ 和 Java 的初学者,所以我对您的示例代码进行了一些重构以帮助您入门。一路上我注意到的事情:

    • 您使用的是非常旧的 AspectJ 版本 1.6.10。它是从 2010 年开始的,甚至不是最新的 1.6 版本(即 1.6.12)。使用当前的 AspectJ 版本 1.8.6 怎么样?
    • 我是一个干净的代码专家,并注意到您的类名相当混淆了您想要通过示例代码演示的内容。所以我重命名了它们:
      • TestApplication
      • TestAspectHelper
      • AspectTestMyAnnotation
      • AspectJTestMethodInterceptor
    • 我还更改了Helper 方法的返回类型,以便返回void 以外的其他内容,以演示下一个问题。
    • 您的@Around 建议的返回类型为void。这样,如果切入点遇到非 void 方法,它就不起作用。我将返回类型更改为Object,并将返回结果的代码更改为proceed(),以便展示如何以更通用的方式完成此操作。
    • 您的@Around 建议总是记录相同的消息。我更新了它以记录实际的连接点信息(在proceed() 调用之前和之后),这样我们就可以在控制台日志中看到发生了什么。
    • 正如 Andy 所说,显然您打算使用注释来匹配带注释的方法和切入点。因此,我将保留范围更改为 RUNTIME
    • 您的切入点针对所有方法执行,包括Application.mainHelper.doItWithout。我将切入点更改为仅带有 @MyAnnotation 或方法名称中带有子字符串“Aspect”的目标方法。
    • 您似乎希望分析方法执行时间并将方法与应用于方面的方面进行比较。无需创建大量 Date 实例并调用 new Date().getTime()(返回毫秒),您只需使用 System.nanoTime()(返回纳秒)即可。
    • 分析时,您想要测量方法执行时间,而不是对象创建时间。因此,我将代码更改为只创建一个 Helper 实例,然后在整个 main 方法中重复使用。
    • Application 类不需要空的默认构造函数,因为它将由 JVM 自动生成。
    • 为了获得有意义的分析结果,您应该使用更多的重复次数(例如一百万次)。我引入了一个名为 LOOP_COUNT 的常量,以简化所有三个循环的操作。
    • 注意!如果你想测量方法执行时间,你不应该在你的方面打印任何东西,因为那样你也会测量向控制台写东西所花费的时间。因此,我已经注释掉了方面的打印语句。您仍然可以激活它们以进行较少的重复次数,以查看发生了什么。

    重构代码:

    package oata;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(value = ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {}
    
    package oata;
    
    import oata.MyAnnotation;
    
    public class Helper {
        public double doItWithout(int i) {
            return Math.acos(i);
        }
    
        @MyAnnotation
        public double doItAnnotated(int i) {
            return Math.acos(i);
        }
    
        public double doItAspect(int i) {
            return Math.acos(i);
        }
    }
    
    package oata;
    
    public class Application {
        private static final int LOOP_COUNT = 100000000;
    
        public static void main(String arg[]) {
            Helper helper = new Helper();
            System.out.printf(
                "Profiling statistics for %,d repetitions%n%n",
                LOOP_COUNT
            );
    
            long startTime = System.nanoTime();
            for (int i = 0; i < LOOP_COUNT; i++)
                helper.doItWithout(i);
            System.out.printf(
                "Method not targeted by aspect:%n    %,15d ns%n",
                System.nanoTime() - startTime
            );
    
            startTime = System.nanoTime();
            for (int i = 0; i < LOOP_COUNT; i++)
                helper.doItAnnotated(i);
            System.out.printf(
                "Method targeted by aspect because it is annotated:%n    %,15d ns%n",
                System.nanoTime() - startTime
            );
    
            startTime = System.nanoTime();
            for (int i = 0; i < LOOP_COUNT; i++)
                helper.doItAspect(i);
            System.out.printf(
                "Method targeted by aspect because of its name:%n    %,15d ns%n",
                System.nanoTime() - startTime
            );
        }
    }
    
    package oata.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class MethodInterceptor {
        @Around("execution(@oata.MyAnnotation * *(..)) || execution(* *Aspect*(..))")
        public Object around(ProceedingJoinPoint jp) throws Throwable {
    //      System.out.println("BEFORE " + jp);
            Object result = jp.proceed();
    //      System.out.println("AFTER  " + jp);
            return result;
        }
    }
    

    启用方面日志语句的 1 次重复示例控制台日志:

    Profiling statistics for 1 repetitions
    
    Method not targeted by aspect:
                153.893 ns
    BEFORE execution(double oata.Helper.doItAnnotated(int))
    AFTER  execution(double oata.Helper.doItAnnotated(int))
    Method targeted by aspect because it is annotated:
              3.102.128 ns
    BEFORE execution(double oata.Helper.doItAspect(int))
    AFTER  execution(double oata.Helper.doItAspect(int))
    Method targeted by aspect because of its name:
                 55.295 ns
    

    正如您在此处看到的,每个方法仅调用一次,结果并不是很确定。

    禁用方面日志语句的 100,000,000(一亿)次重复的示例控制台日志:

    Profiling statistics for 100.000.000 repetitions
    
    Method not targeted by aspect:
            843.407.034 ns
    Method targeted by aspect because it is annotated:
          1.219.571.173 ns
    Method targeted by aspect because of its name:
          1.175.436.574 ns
    

    现在结果更有说服力:没有任何方面的目标的方法比接下来的两个方法执行得更快,后者的执行时间大约相等,为 1.2 秒,这是意料之中的,因为使用的切入点可以在执行期间静态确定编译时间(对于 CTW)或编织时间(对于 LTW)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多