I am trying to use AspectJ in a standalone application but does not seem to work.
Here are the classes I created-
Andy is right with everything he said. Because you seem to be a beginner in AspectJ as well as Java, I have refactored your sample code a bit in order to help you get started. Things I noticed along the way:
Test
→ Application
TestAspect
→ Helper
AspectTest
→ MyAnnotation
AspectJTest
→ MethodInterceptor
Helper
methods' return types so as to return something other than void
in order to demonstrate the next issue.@Around
advice has a return type of void
. This way it does not work if the pointcut hits a non-void method. I changed the return type to Object
and the code to return the result of proceed()
in order to show how this can be done in a more generic way.@Around
advice always logs the same message. I updated it to log the actual joinpoint info (before and after the proceed()
call) so we can see what is happening on the console log.RUNTIME
.Application.main
and Helper.doItWithout
. I changed the pointcut to only target methods either bearing @MyAnnotation
or with a substring "Aspect" in their method name.Date
instances and calling new Date().getTime()
(returns milliseconds) you can just use System.nanoTime()
(returns nanoseconds).Helper
instance which is then reused throughout the main
method.Application
class does not need an empty default constructor because it will be generated automatically by the JVM.LOOP_COUNT
in order to simplify this for all three loops.Refactored code:
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;
}
}
Sample console log for 1 repetition with aspect log statements enabled:
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
As you can see here, the results are not very conclusive with just one call per method.
Sample console log for 100,000,000 (a hundred million) repetitions with aspect log statements disabled:
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
Now the result is more conclusive: The method not targeted by any aspect is executed more quickly than the next two methods which have about equal execution time of 1.2 seconds, which was to be expected because the pointcuts used can be determined statically during compilation time (for CTW) or weaving time (for LTW).
Few things:
META-INF/*
folder definitely being copied to your bin folder where you are running the app from?oata.*
, that will only include direct classes in the oata package, if you want further sub packages (and I think you do) you need oata..*
weaver options="-verbose"
- does that show you anything? If it shows you nothing the aop.xml file is not being found. If it does show you something it will tell you which aspects are being turned on. Perhaps then augment it with -debug
to see more about what is going on.!within(AspectJTest)
complaint to your pointcut or you could end up self advising and failing with a stack overflow when it does start working.SOURCE
retention because AspectJ works at the byte code level and won't see if it has source retention.