AspectJ claims that it is a 'seamless aspect-oriented extension to the Java programming language that enables clean modularization of these crosscutting concerns'. I.e. it is a framework that allows to define aspects at particular manner and inject corresponding instructions directly to the byte code. Historically there was a dedicated aspect description language and extended java compiler that was able to understand it. AspectJ guys also introduced ability to define aspects via java5 annotations later. Feel free to get more information about AspectJ facilities and syntax at the AspectJ documentation page.
The main difference between Spring AOP and AspectJ AOP is that Spring AOP is proxy-based, i.e. it assumes that the client uses AOP-aware proxies instead of the 'raw' objects. That causes the problem I mentioned before. AspectJ injects its instructions directly to the byte code, hence, it doesn't suffer from that.
Spring users can witch to AspectJ immediately in the case of Spring2 AOP usage - spring uses subset of AspectJ pointcut expression language, and @AspectJ spring aspects are fully eligible for AspectJ weaving.
Lets define a simple test-case that shows AspectJ weaving:
What do we want is to see that aspect method is called when TestTarget.test() is invoked.
There are three ways to inject instructions implied by AspectJ aspects:
- compile-time weaving - compile either target source or aspect classes via dedicated aspectj compiler;
- post-compile weaving - inject aspect instructions to already compiled classes;
- load-time weaving - inject aspect instructions to the byte code during class loading, i.e. load instrumented class instead of the 'raw' one;
It's possible to use any of the approaches mentioned above via various ways. I'm big fan of the law of leaky abstractions, so, lets perform weaving at the lowest level at first.
Lets define our directories structure for the example:
Here *.jar files are AspectJ binaries:
- aspectjrt.jar - necessary in runtime for correct aspects processing;
- aspectjtools.jar - contains implementation of aspectj compiler;
- aspectjweaver.jar - bridge between aspectj logic and java instrumentation;
*.xml files are:
- aop.xml - aspectj loadtime descriptor;
- build.xml - ant script;
- pom.xml - maven descriptor;
Compile-time and post-compile-time weaving is performed via ajc tool that stands for aspectj compiler. It allows to weave aspects at compile-time. Feel free to read more about it at its documentation.
It compiles target class and aspect class and runs target class. Following output is produced:
We can see that aspect logic is introduced to the target class.
Note: it is assumed that java remains at the path.
The general idea here is to inject aspect logic to the existing binaries. It's very useful when you work with third-party libraries. AspectJ keeps original byte code untouched and produces the new one with aspect logic inside it.
post-compile-weaving.sh script shows that approach:
This script compiles sources using standard javac compiler and weaves the aspects to the binary code. The output shows that aspect is correctly woven.
Aspects logic is injected to the class byte code during loading classes to the JVM. Standard java instrumentation facilities are used for that. More information about load-time weaving may be found here.
load-time-weaving.sh contains the following instructions:
If we run the example we get the following:
We know now how to weave by hand, lets consider using more convenient ways. The first one is a honorable ant:
We can run 'ant compiletime', 'ant postcompile' and 'ant loadtime' and check that output is pretty much the same as the one from command-line scenarios.
Finally let's consider the most convenient build tool - maven. There is a dedicated aspectj plugin that relieves the job.
If we run 'mvn install' we get the following output:
It's also easy to weave dependencies to the existing jars that are used as a project dependencies - Weaving already compiled jar artifacts
I created an archive that contains the same example that I described before, so, you can simply download it and test - link. Note that the size is ~9.5 MB (because big aspectj binaries are included).