The full list of resolved issues in 1.9.0 is available here.
Key change in 1.9.0.RC2 is actually to be more tolerant of JDK10. The version handling has been somewhat overhauled so AspectJ 9 will behave better on Java 10 and future JDKs. This should put AspectJ in a better place if new JDK versions are going to arrive thick and fast.
This is the first release candidate of AspectJ 1.9.0 - the version of AspectJ to be based on Java9. It includes a recent version of the Eclipse Java9 compiler (from jdt core, commit #062ac5d7a6bf9).
AspectJ can now be used with the new module system available in Java9. The key jars in AspectJ have been given automatic module names. The automatic module name is org.aspectj.runtime for the aspectjrt module:
$ java --module-path <pathto>/lib/aspectjrt.jar --list-modules | grep aspectj
org.aspectj.runtime file:///<pathto>/lib/aspectjrt.jar automatic
And similarly org.aspectj.weaver and org.aspectj.tools for aspectjweaver and aspectjtools respectively:
$ java --module-path <pathto>/lib/aspectjweaver.jar --describe-module org.aspectj.weaver
org.aspectj.weaver file:///<pathto>/lib/aspectjweaver.jar automatic
requires java.base mandated
contains aj.org.objectweb.asm
contains aj.org.objectweb.asm.signature
contains org.aspectj.apache.bcel
contains org.aspectj.apache.bcel.classfile
contains org.aspectj.apache.bcel.classfile.annotation
contains org.aspectj.apache.bcel.generic
contains org.aspectj.apache.bcel.util
contains org.aspectj.asm
contains org.aspectj.asm.internal
...
AspectJ understands module-info.java source files and building modules that include aspects. Here is an example:
module-info.java
module demo {
exports pkg;
requires org.aspectj.runtime;
}
pkg/Demo.java
package pkg;
public class Demo {
public static void main(String[] argv) {
System.out.println("Demo running");
}
}
otherpkg/Azpect.java
package otherpkg;
public aspect Azpect {
before(): execution(* *(..)) && !within(Azpect) {
System.out.println("Azpect running");
}
}
We can now build those into a module:
$ ajc -1.9 module-info.java otherpkg/Azpect.java pkg/Demo.java -outjar demo.jar
...
module-info.java:3 [error] org.aspectj.runtime cannot be resolved to a module
...
Wait, that failed! Yes, aspectjrt.jar (which includes the required org.aspectj.weaver module) wasn't supplied. We need to pass it on the module-path:
$ ajc -1.9 --module-path <pathto>/aspectjrt.jar module-info.java otherpkg/Azpect.java pkg/Demo.java -outjar demo.jar
Now we have a demo module we can run:
$ java --module-path <pathto>/aspectjrt.jar:demo.jar --module demo/pkg.Demo
Azpect running
Demo running
That's it!
A module is really just a jar with a module-info descriptor. As such you can simply pass a module on the inpath and binary weave it with other aspects. Take the module we built above, let's weave into it again:
extra/AnotherAzpect.java
package extra;
public aspect AnotherAzpect {
before(): execution(* *(..)) && !within(*Azpect) {
System.out.println("AnotherAzpect running");
}
}
$ ajc -inpath demo.jar AnotherAzpect.java -outjar newdemo.jar
Notice how there was no complaint here that the org.aspectj.runtime module hadn't been passed in. That is because inpath was being used which doesn't treat specified jars as modules (and so does not check dependencies). There is no module-inpath right now.
Because the new jar produced includes the compiled aspect, the module-info specification inside is still correct, so we can run it exactly as before:
$ java --module-path ~/installs/aspectj190rc1/lib/aspectjrt.jar:newdemo.jar --module demo/pkg.Demo
Azpect running
AnotherAzpect running
Demo running
Dave Syer recently created a series of benchmarks for checking the speed of Spring-AspectJ: https://github.com/dsyer/spring-boot-aspectj
Here we can see the numbers for AspectJ 1.8.11 (on an older Macbook Pro):
Benchmark (scale) Mode Cnt Score Error Units
StartupBenchmark.ltw N/A avgt 10 2.553 ~ 0.030 s/op
StartupBenchmark.ltw_100 N/A avgt 10 2.608 ~ 0.046 s/op
StartupBenchmark.spring v0_10 avgt 10 2.120 ~ 0.148 s/op
StartupBenchmark.spring v1_10 avgt 10 2.219 ~ 0.066 s/op
StartupBenchmark.spring v1_100 avgt 10 2.244 ~ 0.030 s/op
StartupBenchmark.spring v10_50 avgt 10 2.950 ~ 0.026 s/op
StartupBenchmark.spring v20_50 avgt 10 3.854 ~ 0.090 s/op
StartupBenchmark.spring v20_100 avgt 10 4.003 ~ 0.038 s/op
StartupBenchmark.spring a0_10 avgt 10 2.067 ~ 0.019 s/op
StartupBenchmark.spring a1_10 avgt 10 2.724 ~ 0.023 s/op
StartupBenchmark.spring a1_100 avgt 10 2.778 ~ 0.057 s/op
StartupBenchmark.spring a10_50 avgt 10 7.191 ~ 0.134 s/op
StartupBenchmark.spring a10_100 avgt 10 7.191 ~ 0.168 s/op
StartupBenchmark.spring a20_50 avgt 10 11.541 ~ 0.158 s/op
StartupBenchmark.spring a20_100 avgt 10 11.464 ~ 0.157 s/op
So this is the average startup of an app affected by aspects applying to the beans involved.
Where numbers are referenced the first is the number of aspects/pointcuts and the second
is the number of beans. The 'a' indicates an annotation based pointcut vs a non-annotation
based pointcut ('v'). Notice things are much worse for annotation based pointcuts. At 20
pointcuts and 50 beans the app is 9 seconds slower to startup.
In AspectJ 1.8.12 and 1.9.0.RC1 some work has been done here. The key change is to recognize that the use of annotations with runtime retention is much more likely than annotations with class level retention. Retrieving annotations with class retention is costly because we must open the bytes for the class file and dig around in there (vs runtime retention which are immediately accessible by reflection on the types). In 1.8.11 the actual type of the annotation involved in the matching is ignored and the code will fetch *all* the annotations on the type/method/field being matched against. So even if the match is looking for a runtime retention annotation, we were doing the costly thing of fetching any class retention annotations. In 1.8.12/1.9.0.RC1 we take the type of the match annotation into account - allowing us to skip opening the classfiles in many cases. There is also some deeper work on activating caches that were not previously being used correctly but the primary change is factoring in the annotation type.
What difference does that make? AspectJ 1.9.0.RC1:
Benchmark (scale) Mode Cnt Score Error Units
StartupBenchmark.ltw N/A avgt 10 2.568 ~ 0.035 s/op
StartupBenchmark.ltw_100 N/A avgt 10 2.622 ~ 0.075 s/op
StartupBenchmark.spring v0_10 avgt 10 2.096 ~ 0.054 s/op
StartupBenchmark.spring v1_10 avgt 10 2.206 ~ 0.031 s/op
StartupBenchmark.spring v1_100 avgt 10 2.252 ~ 0.025 s/op
StartupBenchmark.spring v10_50 avgt 10 2.979 ~ 0.071 s/op
StartupBenchmark.spring v20_50 avgt 10 3.851 ~ 0.058 s/op
StartupBenchmark.spring v20_100 avgt 10 4.000 ~ 0.046 s/op
StartupBenchmark.spring a0_10 avgt 10 2.071 ~ 0.026 s/op
StartupBenchmark.spring a1_10 avgt 10 2.182 ~ 0.032 s/op
StartupBenchmark.spring a1_100 avgt 10 2.272 ~ 0.024 s/op
StartupBenchmark.spring a10_50 avgt 10 2.557 ~ 0.027 s/op
StartupBenchmark.spring a10_100 avgt 10 2.598 ~ 0.040 s/op
StartupBenchmark.spring a20_50 avgt 10 2.961 ~ 0.043 s/op
StartupBenchmark.spring a20_100 avgt 10 3.093 ~ 0.098 s/op
Look at the a20_100 case - instead of impacting start time by 9 seconds, it impacts it by 1 second.
Eclipse JDT Java 9 support is still being actively worked on and lots of fixes will be coming through over the next few months and included in AspectJ 1.9.X revisions.
AspectJ does not currently modify module-info.java files. An aspect from one module applying to code in another module clearly introduces a dependency between those two modules. There is no reason - other than time! - that this can't be done. (Issue 526244)
Related to that AspectJ, on detection of aspects should be able to automatically introduce the requires org.aspectj.runtime to the module-info. (Issue 526242)
Module aware variants of AspectJ paths: --module-inpath, --module-aspectpath. (Issue 526243)