Getting started with AOP in JBoss 5.1 with a simple example

Introduction

I am writing this post since it took me a while to configure and run my first AOP example in a JBoss application, but I must say after spending some time, I realized it is quite easy, I just couldn’t find a simple example documenting all the needed steps. I hope this post helps you to get quickly started, if that’s the case let me know, or if you ran into other issues. It is always inspiring to read your comments.
In this post I’m not going to introduce Aspect Oriented Programming (AOP), as this is not a recent idea and there are several books you can read. If you need some intro, you can read any of these:

The examples provided in this post will allow you to develop aspects for any class deployed in a JBoss server. If you only want to intercept EJB methods you can use the EJB Interceptors, defined in EJB 3.0. For more info about Interceptors, check out this link and book:

AOP Example in JBoss 5.1

Let’s get started. Reading this link almost did the job, but I still had some things to figure out before everything worked. I also had to take a look at JBoss documentation.
Following these steps you’ll have a very simple and running example of an AOP interceptor which will log calls to methods of a package classes. After having this example up and running, the possibilities are limitless 🙂
I assume you are running with the ‘default’ server configuration. If you use another, you’ll have to ensure you are editing the correct folders (for example, change ‘default’ to ‘all’).

Configure JBoss

  1. Copy the pluggable-instrumentor.jar from the lib/ directory of your JBoss AOP distribution (%JBOSS_PATH%/jboss-as/server/default/deployers/jboss-aop-jboss5.deployer/) to the bin/ directory of your JBoss Enterprise Application Platform.
  2. Edit the startup script of the JBoss server (run.bat or run.sh depending if you are on windows or linux) and add “-javaagent:pluggable-instrumentor.jar” into JAVA_OPTS variable
  3. In case you don’t know, you’ll find this file in %JBOSS_PATH%/jboss-as/bin/.

  4. Edit %JBOSS_PATH%/jboss-as/server/default/conf/bootstrap/aop.xml:
    1. Set the element enableLoadtimeWeaving to “true”
    2. The property will look like

      	<property name="enableLoadtimeWeaving">true</property>
      	
    3. Add to the element include the package you want to instrument or intercept
    4. By default, all packages not listed in the exclude property will be intercepted, so you may skip this step.
      If you choose to explicitly list your package (ie com.mypackage and all subpackages), the include property will look like:

      	<property name="include">org.jboss.test., org.jboss.injbossaop. , com.mypackage. </property>
      	

This is enough to make JBoss run AOP every time you run it with the start scipt. If you want to enable AOP interceptors when running JBoss from Eclipse, you will need to add -javaagent:pluggable-instrumentor.jar to the VM arguments in the server properties.

Logger interceptor

Now, lets build our first AOP interceptor, which will add a log to every call to methods in package and subpackages of com.mypackage.
First, we create an interceptor, a simple Java class which implements org.jboss.aop.advice.Interceptor. In this class we will call invokeNext() to call the original method and log the time taken to run. This is the code:

package com;

import org.apache.log4j.Logger;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.joinpoint.Invocation;
import org.jboss.aop.joinpoint.MethodInvocation;

public class LogInterceptor implements Interceptor {

	@Override
	public String getName() {
		return "LogInterceptor";
	}

	static Logger logger = Logger.getLogger(LogInterceptor.class);

	@Override
	public Object invoke(Invocation invocation) throws Throwable {
		long time = System.currentTimeMillis();
		try {
			// NEVER FORGET TO CALL invokeNext()
			// unless you want to cancel the call to the destination method
			// (i.e.: a security interceptor)
			return invocation.invokeNext();
		} finally {
			time = System.currentTimeMillis() - time;
			if (invocation instanceof MethodInvocation) {
				MethodInvocation mi = (MethodInvocation) invocation;
				String clazz = "";
				String method = "";
				try {
					clazz = mi.getTargetObject().getClass().toString();
					method = mi.getMethod().getName();
				} catch (Throwable e) {
					logger.error("Error when trying to get target info");
				}
				logger.info("LogInterceptor: " + time + "ms - class: " + clazz
						+ " method: " + method);
			}
		}
	}
}

After this, we create a jboss-aop.xml which will look like this (we are just defining the interceptor and creating a pointcut, which defines when the interceptor will be called):

<?xml version="1.0" encoding="UTF-8"?>
<aop xmlns="urn:jboss:aop-beans:1.0">
  <interceptor name="Int" class="com.LogInterceptor"/>
  <bind pointcut="execution(* com.mypackage.*->*(..))">
    <interceptor-ref name="Int"/>
  </bind >
</aop>

This defines a pointcut to all methods inside package com.mypackage, no matter their return type or parameters. Later on this post I’ll add some more examples of pointcuts for you to narrow down the list of intercepted methods.

After compiling com.LogInterceptor, we’ll just create a jar file, for example aopExample.jar which will contain these files and folders:

com
	LogInterceptor.class
META-INF
	jboss-aop.xml

After this, copy this jar file into the deploy folder together with your application, restart your jboss server, and after running the application (classes inside com.mypackage) you’ll start seeing these logs in JBoss:

21:59:22,254 INFO  [LogInterceptor] LogInterceptor: 2ms - class: class com.mypackage.Hello method: doGet
22:04:43,637 INFO  [LogInterceptor] LogInterceptor: 0ms - class: class com.mypackage.Hello method: doGet

If you want to quickly test this, you can download my testAop.jar and my test application TestWeb.war and put them in your JBoss server.
Here are the links:
testAop.jar
TestWeb.war

TestWeb.war has only one servlet: com.mypackage.Hello which prints Hello world in the browser. The important part here is that testAop.jar is intercepting calls to TestWeb.war. Just point your browser to http://localhost:8180/TestWeb/Hello and look at the server log.

Starting with this example, you can start doing more complex things with AOP, from logging how long it takes a method to run, to creating a security framework.

Pointcuts

Here are some examples of pointcuts if you want to start playing around with these:

  • <bind pointcut=”execution(* com.mypackage.*->*(..))”>
  • Will intercept any method call inside the package com.mypackage.

  • <bind pointcut=”execution(* com.mypackage.MyClass->*(..))”>
  • Will intercept any method call to the class com.mypackage.MyClass

  • <bind pointcut=”execution(* com.mypackage.MyClass->myMethod(..))”&gt
  • Will intercept the method myMethod (with any combination of parameters and return type) in class MyClass .

Interceptor API

When developing an interceptor, you can use the API to access important information regarding the intercepted invocation. You can change the original parameters of the invocation, change the return value, and have access to the destination (class and method) information.

At the invoke(Invocation mi) method, if Invocation is instance of MethodInvocation you can call:

mi.getTargetObject().getClass() to get the intercepted class intercepted.

mi.getMethod().getName() to get the method name which is being intercepted.

Advertisements