Monday, June 30, 2008

Dynamic AOP Tutorial - Part 1

The goal of this tutorial is to show how to use dynamic AOP with JBoss AOP. Notice that, by dynamic AOP, we mean the dynamic weaving of aspects, and not dynamic pointcut expressions (such as cflow), as other tools refer to them using the same term.

There are two ways of using dynamic AOP with JBoss AOP: hot deployment (when running your application in AS); or through our API.

In the next topics, we will show what are the prerequisites for dynamic AOP, and how to use hot deployment of aspects at the server. In the second part of our tutorial, we will see how to use our API to perform dynamic operations.

What is Dynamic AOP?

Dynamic AOP or dynamic weaving consists of adding/removing aspects to/from your system at runtime, without need for recompilation or rebooting.

In practice, this means that you can enable and disable aspects at runtime, including aspects previously unknown to your system. There are several scenarios where this functionality comes in handy. For example, to debug failures that show up only after your application has been running for a long time. In a situation like this, a lot of time could be saved as dynamic AOP will not require the system to be rebooted in order to attach an aspect to debug your application. Furthermore, dynamic AOP allows the runtime addition of extensions to a system that cannot be rebooted frequently. Another example of applicability is to fix an aspect that contains a bug, or that needs to have its functionality extended at runtime.

JBoss AOP supports dynamic AOP by rebuilding interceptor chains associated with a joinpoint when aspects are added and/or removed. If hot swap is enabled, JBoss AOP also instruments the code at runtime to insert/remove invocations to these chains whenever appropriate. Otherwise, the calls to chains are inserted during compilation or class loading (depending on whether you are using compile time or load time weaving).

Preparing your Application for Dynamic AOP

In order to perform dynamic AOP operations, JBoss AOP must know beforehand which joinpoints need to be instrumented, so that the invocations to interceptor chains are added to the code before it gets executed.
This restriction applies even with hot swap enabled. Due to security constraints of the JVM, the list of methods, constructors, and fields of a class cannot change at runtime. Nor can their signatures. For weaving, JBoss AOP inserts auxiliary fields and methods into your class bytecodes. Given the JVM constraints, this step must be performed before your code gets executed and, hence, the joinpoints to be instrumented must be known at the first weaving stage (compile time or loadtime weaving).

To indicate which joinpoints must be instrumented for dynamic AOP, you must use prepare expressions. A prepare expression can be declared either in an xml file or as an annotation. Look at the example below:

  <prepare expr="all(Pojo)"/>

This is the content of a jboss-aop.xml file. This file contains a single declaration of a prepare expression, but it could contain as many as you wish. Naturally, it could contain as well tags for non-dynamic AOP purposes, such as pointcuts, bindings, introductions, etc.

Prepare expressions can also be declared in the form of annotations:

@Aspect(scope = Scope.PER_VM)
public class MyAspect
  @Prepare ("all(Pojo)")
  public static Pointcut preparePOJO;

  public static Pointcut aPointcut;

Notice above the similarity in the syntax of the declaration of a prepare expression, with the @Prepare annotation, and of a pointcut expression, with the @PointcutDef expression. Except for the annotation used, their syntax is the same.

The annotation @Prepare can also be used to annotate plain-old Java classes:

public class Pojo

In this case, it indicates that the method execution and field access joinpoints contained in Pojo class must be prepared for runtime weaving of aspects.

Joinpoints matched by plain pointcut expressions can also be the target of dynamic AOP operations. JBoss AOP treats joinpoints matched by pointcuts and joinpoints matched by prepare expression in a very similar way.

The main difference between the two types of expressions lies in their semantic meaning. When you run across a prepare expression, you immediately know that it is being declared for dynamic AOP purposes. On the other hand, if you see a pointcut expression you expect it to be used in one or more bindings. For readability, always prefer to use prepare expressions over plain pointcuts to indicate dynamic AOP usage.

In addition, JBoss AOP does not affect the control flow of joinpoints matched by prepare expressions when using hot swap. The control flow of those joinpoints will be affected only after a dynamic aspect addition is performed, which means you will have a better performance when prepare expressions are used appropriately.

Hot Deployment of Aspects

Hot deployment is the most straightforward way of using dynamic AOP with JBoss AOP, and is available for JBoss AS.

In JBoss AS, all deployment units, such as ears, wars, jars, can be hot deployed. JBoss AS will automatically load the applications added to the deploy folder, and unload them when their units are removed from the deploy folder.

The JBoss AOP deployment units have the .aop suffix. By deploying such an unit at runtime, the aspects contained in it will be automatically deployed to all prepared joinpoints of the previously deployed applications. If you are running the server with load time weaving, all the applications deployed after this moment will also be instrumented by JBoss AOP to insert the aspects contained in the deployment unit, according to the bindings and pointcuts it contains.
Similarly, when a .aop file is removed from the deploy dir, the bindings it contains will be automatically removed from the running applications.

As an alternative to using .aop units, you can use other deployment units and xml files to hot deploy aspects to the server. In this case, the aspect classes are bundled into a non-aop deployment unit (such as a .jar or an .ear) and deployed to the server. The binding declarations are deployed to the server separately in an xml file whose name must end with -aop.xml. The effect of this two-part deployment is the same as you get by deploying an .aop file, but with one advantage. This type of deployment allows you to redeploy only the *-aop.xml file, without causing the aspect classes to be reloaded. The simple removal of your *-aop.xml file will cause the bindings to be undeployed. And the addition of a new *-aop.xml file will cause the bindings declared in it to be deployed to the server.

Wrapping up

In a nutshell, we have seen that:

  • only joinpoints matched by prepare and pointcut expressions during compile/load time weaving can be the target of dynamic operations.

  • to use dynamic aop in the AS, you can deploy and undeploy .aop files.

  • an alternative is to deploy xml files ending in -aop.xml, containing the declarations of bindings and pointcut expressions.

Next Steps

Take a look at the injboss example, available as part of the JBoss AOP documentation. It shows the different ways of packaging aspectized applications to be run in JBoss AS. Try running those examples and playing with dynamic AOP to see it in action! (For example, run $ ant deploy-basic-lt-war and try removing the jboss-aop.xml file from your server deploy dir in order to have the aspects undeployed)

In the next part of the tutorial, we will show how to use the JBoss AOP API to perform dynamic AOP operations. Stay tuned!