Applying AspectJ to an Existing Codebase
AspectJ comes as a standalone toolkit including the AspectJ compiler and a runtime jar that is required to execute AOP programs. AJDT is the AspectJ plugin for Eclipse. It builds on the standalone toolkit providing further support for AOP inside Eclipse through specialized editors and views.
As an Eclipse user my first inclination was to try AJDT to get the benefits of an IDE I am used to such as typing support, syntax checking, incremental compilation, navigation, etc. After trying AJDT on an existing project I was generally impressed with what AOP can do and wanted to keep experimenting. However I also realized that working with existing especially larger code bases can be problematic.
For once the AspectJ compiler, which needs to examine all classes targeted for code weaving is hungry for memory. While the standalone compiler releases memory as soon as it's done compiling, the AJDT plugin used the same amount of memory but didn't release it. Furthermore, the overall performance of Eclipse was impacted adversely when various views (especially the Project Explorer view) came in and out of view.
Since I was really keen on using AspectJ on a real-world, living codebase the above issues were unacceptable to me. I needed to find a way I could conveniently apply AspectJ to my existing Java projects without converting them to the AJDT project type hence bringing the potential to disrupt my regular work.
After some experimentation I arrived at a solution utilizing only the AspectJ toolkit and an Ant build file. The solution allows you to keep experimenting with AspectJ on an existing codebase while retaining the flexibility to run without any aspects at all. With it I still use Eclipse to organize aspect source files as well as to run the Ant build. However, I no longer take advantage of specialized AOP viewing and editing features inside Eclipse. This is okay because the AspectJ compiler can produce sufficient information for me to be able to look at what classes aspects were woven into.
Here is a high-level description of the solution:
- Keep your existing Java codebase setup unmodified.
- Create a separate project (or even workspace) to hold aspect source files.
- Use Ant to run the AspectJ compiler on your existing codebase.
- Point the AspectJ compiler to the compiled classes of your existing Java codebase.
- Point the AspectJ compiler to an output directory that is different from the compiled classes of your existing Java codebase.
- Use the classpath of your application to control whether you run with or without AspectJ compiled classes.
A few slightly more detailed tips:
- Use a "Simple" Eclipse project to hold aspect sources (.aj).
- Keep logic in aspect source files to a minimum and delegate to supporting Java classes as soon as possible.
- Keep pointcut definitions separate from other aspect sources - it makes it easier to re-use them.
- Use argument files (.lst) to control what aspects are included in the compilation.
- Use a separate argument file for pointcut definitions - this argument file can be supplied to the AspectJ compiler unconditionally (i.e. with every compilation).
- Point the AspectJ compiler to the compiled classes of your existing code base - this makes the compilation a little faster and also gives you the option to alternate between using or not using your aspects at runtime by altering the classpath of your application.
Here is a sample ant target for invoking the AspectJ compiler supporting the above guidelines :
<target name="compile">
<taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
<classpath>
<pathelement location="${aspectj.home}/lib/aspectjtools.jar"/>
</classpath>
</taskdef>
<iajc destDir="${aop.output}" Xlintwarnings ="true" showWeaveInfo="true">
<argfiles>
<pathelement location="${aop.project}/myAspectSources.lst"/>
<pathelement location="${aop.project}/myPointcutSources.lst"/>
</argfiles>
<inpath>
<pathelement location="${java.output}"/>
</inpath>
<classpath>
<pathelement location="${aspectj.home}/lib/aspectjrt.jar"/>
<path refid="java.classpath"/>
</classpath>
</iajc>
</target>
Things to notice in the above ant target:
- Xlintwarnings and showWeaveInfo are two compiler options providing invaluable compiler output. You will want to know what classes were affected by your aspects.
- aspectj.home is the directory where the AspecJ toolkit was unzipped
- aop.output is the output directory for the AspectJ compiler
- java.output is the directory with compiled classes from your existing Java codebase are located
- java.classpath is the complete classpath required for compiling your
existing Java codebase (the AspectJ compiler needs this).
Note: There is a quick way to generate this classpath. Assuming your existing codebase is in an Eclipse workspace you can use 'File > Export... > Ant buildfiles' to generate a build.xml from which you can copy the classpath elements. - myAspectSources.lst and myPointcutSources.lst contain listings of aspect source files (one per line) to be included in the compilation.