Lightweight AOP with plain Java SE 1.3+, without additional libraries, frameworks and tools

Aspect Oriented Programming is often used for trivial things like logging, static security checks or performance measurements.
Although AOP separates the infrastructure from the business and so makes the code more maintainable, it introduces also some additional complexity. AOP relies on (static/dynamic) bytecode manipulation often with own classloaders or java agents. This can be funny in managed environments like RCP-Frameworks or Java EE containers :-).
Also some additional libraries have also be shipped, which introduces some risk in the deployment.

Interestingly enough: Java has already a built-in a simple interception mechanism called: dynamic proxy. It is actually very old (since JDK 1.3+), so it seems to be almost forgotten.
The key element is one simple interface from the package java.lang.reflect, called InvocationHandler. It comes with a simplistic method:  

public Object invoke(Object proxy, Method method, Object[] args)    throws Throwable;

This Handler-interface has to be realized by a custom class which in fact already represents the cross cutting aspect. In our case it is a simple logger:

public class TracingInvocationHandler implements InvocationHandler{

    public Object invoke(Object proxy, Method method, Object parameters[])
        throws Throwable {
            Object retVal;
            Method targetMethod = null;
                try {
                long start = System.currentTimeMillis();
                System.out.println("Invoking: " + formatMethodOutput(method,parameters));
                targetMethod = getMethodForTarget(method,method.getParameterTypes());
                retVal = targetMethod.invoke(target, parameters);
                //performance mesurement
                } catch (InvocationTargetException e) {
                 //Exception reporting 
                        e.getTargetException().toString());
                 //rethrowing the exception
                    throw e.getTargetException();
                } catch (Exception e) {
                    throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
                }   
        return retVal;
    }


Now we have to somehow inject this additional behavior to the existing Java-code. This can be done with the static method java.lang.reflect.Proxy.newProxyInstance.
And now some limitation of this approach are visible:

  1. The Proxy-class is only able to decorate interfaces
  2. It is hard to inject the additional behavior to existing spaghetti code...
However, existing factories are perfect place for the product decoration. The decoration can be also factored out into a utility. Then we are even able to intercept JDK-classes (the class Decorator only wraps the Proxy.newProxyInstance methods and simplyfies the user interface):

        Map map =(Map) Decorator.trace(new HashMap(),Map.class);
    System.out.println("Map: "  +map.getClass().getName());
    map.put("hallo","world");
    map.get("hallo");
    map.size();

The execution of this piece of code creates the following output:

Map: $Proxy0
Invoking: java.lang.Object java.util.Map.put(java.lang.String hallo,java.lang.String world)
put returns: null performed in: 0 ms!
Invoking: java.lang.Object java.util.Map.get(java.lang.String hallo)
get returns: world performed in: 0 ms!
Invoking: int java.util.Map.size()
size returns: 1 performed in: 0 ms!

You will find the whole, fully functional, project in p4j5 (Check-Out the DynamicProxy NB-project and "run" it).

Comments:

Hi Adam

Fair enough, maybe there are some Java developers out there that don't know about the Proxy class and it's applications, so your post is good in that regard.

However, AOP is much more than just an interception mechanism (which is all that the Proxy class provides). The pointcut notion is key to AOP, and the Proxy class as-is provides no such pointcut mechanism.

Spring AOP is an AOP framework that *by default* uses the Proxy interception mechanism described in your post, and so it is somewhat wrong to say that 'AOP relies on (static/dynamic) bytecode manipulation'. Spring AOP (by way of an example) *can* switch to interception via bytecode manipulation, but it is not a hard requirement (of Spring AOP and of the AOP paradigm in general.

Cheers
Rick

Posted by Rick Evans on August 13, 2007 at 03:33 PM CEST #

Hi Rick,

0. There are many Java developers, which do not know dynamic proxy :-).
1. Is Spring AOP also able to intercept classes without weaving with dynamic proxy?
2. You are right - but it only works for interfaces, or?

thank you very much for your comment,

Posted by Adam Bien on August 13, 2007 at 03:49 PM CEST #

Hi Adam,

0. I'm not sure if there are so much java developers which do not know Dynamic Proxy nowadays. Of course this is not representative, but i can say that there are no developers in my environment which haven't heard about Dynamic Proxy so far. Actually, the issue behind is an interessting one: how many so called 'java experts' are unaware of the so called 'core' libraries (like Collections and so on).

1. yes, this might be also possible using CGLIB, as far as your classes you want to advice are not final.

2. see 1. (CGLIB is weaving in adviced code by extending classes)

Greetings

Mario

Posted by Mario Gleichmann on August 20, 2007 at 12:30 AM CEST #

Hi Adam,
I want develop AspectJ with JSF 1.2 without integrating with spring frame work. is it possible if so could you tell me the workaround details and configuration details.

Posted by sridhar on October 15, 2011 at 12:00 PM CEST #

Hello Adam,

Could you please share example application. The given link is not working actually.

Cheers,
Aijaz

Posted by Aijaz on November 20, 2014 at 06:57 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License