Aspect deployment descriptor - META-INF/aop.xml

Since release 1.0 AspectWerkz support to configure several AspectSystem alongside the deployed applications and the container (application server) in which those are deployed. As described here, you need to write an AOP XML deployement descriptor for your aspects, that declares the Aspects to use, and defines or refines the pointcuts (where to do) and advices (what to do), no matter your Aspects are using an annotations based definition or a full XML defintions, or both.

When thinking about this aop.xml file, you need to remember that the declared Aspects will affect the classes visible from the ClassLoader that can access this file. For example if you package this file in application.war/WEB-INF/aop.xml, it will affect all web-application classes, third parties libraries from application.war/WEB-INF/lib/ and all JSPs.

If you want to affect all JVM classes, you can use the JVM option -Daspectwerkz.definition.file=path/aop.xml, or better have one or more META-INF/aop.xml file(s) accessible from the JVM regular classpath.

It is thus possible to organise your aspects alongside all your deployed applications, while allowing some interesting schemes: a tracing Aspect deployed at the JVM level will affect all deployed applications, while Aspects deployed within the application itself will only affect this application.

If you plan to use offline mode, you need to post process your application as many time as you have aop.xml files, and still packaged the aop.xml file(s) alongside the application and/or at a JVM wide level, depending on what you want to achieve.

To summarize, you have to remember that an META-INF/aop.xml or WEB-INF/aop.xml file will affect the classes loaded by the classloader(s) that have this aop.xml file in their path. The JVM wide aop.xml file will affect the system classloader and all child classloaders.

Understanding class loading in Java

You should be familiar with the way Java handles ClassLoader isolation to fully understand how to deploy your own Aspects.

When you are invoking a main method of a Class, this class is loaded (and lives) in the System ClassLoader. All classes belonging to a path specified with a -cp or -classpath JVM option will live in this ClassLoader.

If this class is using java.lang.Object and other java.* classes, those have been loaded (and live) in Extension ClassLoader or Bootstrap ClassLoader.

The java.lang.Object can be seen and used by your main Class since the System ClassLoader is by convention a child of the Extension ClassLoader which is himself a child of the Boot ClassLoader. This relation looks like this:
					Boot ClassLoader (JRE / JDK classes)
						|
					Extension ClassLoader (JRE extension, like SSL security etc, in jre/ext directory)
						|
					System ClassLoader (your main Class, and all the -cp / -classpath jars and classes)
                    

When you are using an application server, there are usually many other classloaders. A simple view is to say that there is one classloader per deployed application (that's why you don't need to add your war file in the JVM classpath right ?). In fact the picture is a bit more complex to allow JSPs changes while the application is running etc. Those application ClassLoaders are child of upper ClassLoaders like the System ClassLoader, but if you deploy two war files, they cannot share classes unless thoses classes are in an upper ClassLoader.

If we deploy two war file in a Tomcat we will end-up in the following (simplified) organization:
					Boot ClassLoader (JRE / JDK classes)
						|
					Extension ClassLoader (JRE extension, like SSL security etc, in jre/ext directory)
						|
					System ClassLoader (the Tomcat main Class, and all the -cp / -classpath jars and classes)
						|
					Some Tomcat specific ClassLoader (does not really matters)
								|                                   |
						  First.war ClassLoader               Second.war ClassLoader
								|                                    |
						  WEB-INF/lib                            WEB-INF/lib
						 and WEB-INF/classes                    and WEB-INF/classes
						 ClassLoader                            ClassLoader for Second.war
								|   |                                 |   |   |
						 JSP ClassLoader(s)                     JSP ClassLoader(s)
                    

For J2EE / EJB based application, the schemes is a bit more complex but follows the same model.

Although this kind of organization is mainly J2EE oriented, some Swing based application are using ClassLoader parent-child relation to allow for example plugin life cycles etc.

Weaving scope of the META-INF/aop.xml and WEB-INF/aop.xml files

The single idea you need to remember is that AspectWerkz deployed Aspects thru aop.xml files have the scope of the ClassLoader that has this file in its path and all its child ClassLoader(s).

Three specific paths are used:

  • JVM wide: defined with -Daspectwerkz.definition.file=path/aop.xml, it impacts all JVM classes (except boot classloader for convenience). Note that it is not mandatory to name the file aop.xml
  • defined with WEB-INF/aop.xml, it will impact the classes of the web application including JSPs. It is mandatory to name the file aop.xml
  • defined with META-INF/aop.xml, it will impact the classes that can see this file. It is mandatory to name the file aop.xml
It is thus possible to place a path/META-INF/aop.xml in the JVM classpath ( -cp path/;...) to have the same scope as the JVM wide defined one.

If a jar file of the JVM classpath contains a META-INF/aop.xml file, it will aslo have the same scope.

The precedence between the aspects is then the one of the classpath, and then the one of the order in the aop.xml file.

With this model, it is thus possible to package a tracing aspect in a jar file, with a META-INF/aop.xml file (with a pointcut for all public method execution f.e.) and just add it to your classpath to allow a very simple generic tracing !

Aspect systems

A single aop.xml file can declare several Aspect Systems for convenience. All will have the same weaving scope. The goal is mainly to have a well organized namespace for organizing your aspects. The precedence will follow the order of the <system> elements in the XML file. Each system must have a unique id within a ClassLoader hierarchy, as defined with <system id="some/system">

In the following two systems are defined, and the system id is using the application name and a path as a mnemonic, allthough it could be any string.
<aspectwerkz>
    <system id="First.war/WEB-INF/FirstSystem">
        <package name="examples">
            <aspect class="caching.CachingAspect" deployment-model="perInstance"/>
        </package>
    </system>
    <system id="First.war/WEB-INF/SecondSystem">
        <aspect class="examples.trace.TracingAspect" deployment-model="perJVM"/>
    </system>
</aspectwerkz>