Aspects

Overview

The Interceptor classes shown in previous examples are a little limiting in that you can only have one advice per class. JBossAOP allows you to group advices into one Java class. This is what JBossAOP calls an Aspect. An Aspect is a collection of advices expressed as methods.

Writing an aspect

An aspect class is a plain Java class. It does not have to inherit from anything, but it must have an empty constructor. Each advice must follow this format:

  public Object <any-method-name>(<any Invocation type>) Throwable

You can also overload methods.

Scope and XML definitions

You can specify the scope of an aspect's instance. By Scope, I mean whether the aspect is allocated once per JVM, once per Class it is tied to, or once per Instance. You must declare an aspect definition in XML. The Scope is optional and defaults to once per JVM. Open up jboss-aop.xml to see declarations of aspects.

   <aspect class="AspectPerVM" scope="PER_VM"/>
   <aspect class="AspectPerClass" scope="PER_CLASS"/>
   <aspect class="AspectPerInstance" scope="PER_INSTANCE"/>

There are three aspect classes. They all count field, method and constructor accesses from within themselves.

You bind specific advices by referencing the method names within advice bindings. jboss-aop.xml again gives examples of this

   <bind pointcut="execution(POJO*->new())">
       <advice name="constructorAdvice" aspect="AspectPerVM"/>
       <advice name="constructorAdvice" aspect="AspectPerClass"/>
   </bind>

The above binding states that whenever a POJO or POJO2's constructor get's invoked call the method constructorAdvice on the AspectPerVM class and the method constructorAdvice on the AspectPerClass object. Remember, because of the scope defined, AspectPerVM will be allocated once for the entire VM. Any bindings that reference advices within that aspect class will share the same AspectPerVM instance. There is one AspectPerClass instance per class it is bound to. So there is an AspectPerClass instance for POJO and POJO2.

   <bind pointcut="execution(void POJO*->someMethod())">
       <advice name="methodAdvice" aspect="AspectPerVM"/>
       <advice name="methodAdvice" aspect="AspectPerClass"/>
       <advice name="methodAdvice" aspect="AspectPerInstance"/>
   </bind>

   <bind pointcut="field(* POJO*->field)">
       <advice name="fieldAdvice" aspect="AspectPerVM"/>
       <advice name="fieldAdvice" aspect="AspectPerClass"/>
       <advice name="fieldAdvice" aspect="AspectPerInstance"/>
   </bind>

The final two bindings intercept field and method access of POJO and POJO2.

Run the example

To compile and run:
  $ ant
It will javac the files and then run the AOPC precompiler to manipulate the bytecode, then finally run the example. The output should read as follows:
run:
     [java] ---- POJO ---
     [java] AspectPerVM.constructorAdvice accessing: public POJO()
     [java] AspectPerClass.constructorAdvice accessing: public POJO()
     [java] empty constructor
     [java] AspectPerVM.fieldAdvice reading field: field
     [java] AspectPerClass.fieldAdvice reading field: field
     [java] AspectPerInstance.fieldAdvice reading field: field
     [java] AspectPerVM.fieldAdvice writing to field: field
     [java] AspectPerClass.fieldAdvice writing to field: field
     [java] AspectPerInstance.fieldAdvice writing to field: field
     [java] AspectPerVM.methodAdvice accessing: public void POJO.someMethod()
     [java] AspectPerClass.methodAdvice accessing: public void POJO.someMethod()
     [java] AspectPerInstance.methodAdvice accessing: public void POJO.someMethod()
     [java] someMethod
     [java] ---- POJO2 ---
     [java] AspectPerVM.constructorAdvice accessing: public POJO2()
     [java] AspectPerClass.constructorAdvice accessing: public POJO2()
     [java] POJO2 empty constructor
     [java] AspectPerVM.fieldAdvice reading field: field
     [java] AspectPerClass.fieldAdvice reading field: field
     [java] AspectPerInstance.fieldAdvice reading field: field
     [java] AspectPerVM.fieldAdvice writing to field: field
     [java] AspectPerClass.fieldAdvice writing to field: field
     [java] AspectPerInstance.fieldAdvice writing to field: field
     [java] AspectPerVM.methodAdvice accessing: public void POJO2.someMethod()
     [java] AspectPerClass.methodAdvice accessing: public void POJO2.someMethod()
     [java] AspectPerInstance.methodAdvice accessing: public void POJO2.someMethod()
     [java] POJO2 someMethod
     [java] -- get stats --
     [java] perVM stats: 2 2 2 2
     [java] POJO perClass stats: 1 1 1 1
     [java] POJO2 perClass stats: 1 1 1 1
     [java] pojo perInstance stats: 1 1 1
     [java] pojo2 perInstance stats: 1 1 1