AspectW方面不适用于LTW方案

时间:2015-08-22 15:29:06

标签: java aspectj load-time-weaving

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

以下是我创建的课程 -

private void button1_Click(object sender, EventArgs e)
{
    WebClient proxy = new WebClient();
    string serviceURL =
            string.Format("http://localhost:53215/IBookService.svc/GetBooksNames");
    byte[] data = proxy.DownloadData(serviceURL);

    var jsonString = Encoding.UTF8.GetString(data);
    IList<string> bookNames = JArray.Parse(jsonString).ToObject<IList<string>>();

    //Do something with the list
    //foreach (string bookName in bookNames)
    //{

    //}    
}
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);

    }
}

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

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));
    }
}

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

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

任何人都可以让我知道我做错了什么。

由于 AA

1 个答案:

答案 0 :(得分:1)

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

  • 您使用的是非常古老的AspectJ版本1.6.10。它是从2010年开始,甚至不是最新的1.6版本(1.6.12)。如何使用当前的AspectJ版本1.8.6?
  • 我是一个干净的代码人,并注意到你的类名相当模糊了你想用示例代码演示的内容。所以我重命名了:
    • TestApplication
    • TestAspectHelper
    • AspectTestMyAnnotation
    • AspectJTestMethodInterceptor
  • 我还更改了Helper种方法'的返回类型,以便返回void以外的其他内容,以便演示下一期。
  • 您的@Around建议的返回类型为void。这样,如果切入点击非空方法,它就不起作用。我将返回类型更改为Object,并将代码更改为proceed(),以便显示如何以更通用的方式完成此操作。
  • 您的@Around建议始终记录相同的消息。我更新了它以记录实际的连接点信息(在proceed()调用之前和之后),以便我们可以看到控制台日志上发生了什么。
  • 正如安迪所说,显然你打算使用注释来将注释方法与切入点相匹配。因此,我将保留范围更改为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)。