We Are Reactive

AWProxy: Proxy on steroids

AWProxy: Proxy on steroids

Summary

Proxies are an important piece in the J2EE puzzle. Since it offers a non-intrusive an more transparent way of weaving in advice/interceptors. However, non of the current proxy implementations utilizes all the rich semantics of AOP (as defined by AspectJ), the expressiveness of a real pointcut pattern language and has the speed of statically compiled code.

AW Proxy is here to try to narrow this gap. It makes use of the rich semantics for AOP in AspectWerkz and is very high-performant due to the use of static compilation (utilizing the AspectWerkz weaver). All wrapped up a very simple and intuitive API.

The need for proxies

The two arguments against load-time weaving that we hear the most are:

Adding the possibility of using AspectWerkz together with proxies is something that Alex and I have been talking about for a long time but never implemented due to lack of time. Well, this weekend I took the time and it was actually more simple than I thought.

After a couple of hours coding (taking the cglib route with its “class proxy”, e.g creating a new class on-the-fly that extends the target class and which methods and constructors delegates to the base class’ methods, but with the difference that they don’t wrap the arguments but pass them on as they are, which gives a lot better performance), I had a working solution.

Introducing AW Proxy

The benefit with using the AspectWerkz Proxies compared to the regular load time weaving is that there are no VM options. You simply create your proxy and before it is returned to you it is weaved with the aspects that happens to be available on the classpath at that time.

The API is pretty straight forward. All you need is in the


org.codehaus.aspectwerkz.proxy.Proxy

class which has the following API:

// Returns a new proxy for the class specified
public static Object newInstance(Class clazz);

// Returns a new proxy for the class specified, instantiates it by invoking the constructor // with the argument list specified public static Object newInstance(Class clazz, Class[] argumentTypes, Object[] argumentValues); // Same as above, but with optional parameters for caching and making the proxy advisable public static Object newInstance(Class clazz, boolean useCache, boolean makeAdvisable); // Same as above, but with optional parameters for caching and making the proxy advisable public static Object newInstance(Class clazz, Class[] argumentTypes, Object[] argumentValues, boolean useCache, boolean makeAdvisable);

How to use the API?

Here is a little example on how to use the Proxy API:


// creates and instantiates a new proxy for the class Target
Target target = (Target) Proxy.newInstance(Target.class, false);

That’s it!

This target instance have now been advised with all the aspects that have been found on the classpath that matches the members of the Target class.

Utilizing programmatic runtime deployment

As I said before, when you create your proxy it will get automatically weaved with all the matching aspects that are found (on the classpath). This is most of the time what you want and need, but there might be cases when you want to add a specific feature, at runtime, to a specfific instance only. In these cases you need programmatic runtime per instance deployment.

One of the new features in the AspectWerkz 2 architecture is that it comes with a full-blown interception framework that allows per instance programmatic deployment with most of the AOP semantics preserved.

In short you will get:

Per instance programmatic deployment for before, around, after, after finally and after throwing advice types for call, execution, set and get pointcuts as well as the expressiveness of the AspectWerkz’ pointcut pattern language all wrapped up in a very simple and intuitive API.

    POJO pojo = new POJO();

    // adds tracing to all methods in the 'pojo' instance
    ((Advisable) pojo).aw_addAdvice(
        "* *.*(..)",
        new BeforeAdvice() {
            public Object invoke(JoinPoint jp) {
                System.out.println("Entering: " + jp.getSignature().toString());
            }
        }
    );

The advice “interceptors” that are supported are:

Now we can combine use this feature together with the AW Proxies. All proxies that are created implements the Advisable interface which makes it really easy and straightforward to use them together:

Example

In this example we create and instantiate a new proxy for the class Target, we set it to become advisable (e.g. it will implement the Advisable interface transparently), and then we add an after returning advice to all methods that returns an instance of java.lang.String.

Advisable target = (Advisable) Proxy.newInstance(Target.class, true, true); target.aw_addAdvice( “String .(..)”, new AfterReturningAdvice() { public void invoke(JoinPoint jp, Object returnValue) { // do some stuff } } );

Benefits

Plain proxies with rich AOP semantics

The benefits are, besides a less intrusive and more transparent approach, that you can utilize the rich semantics for AOP (well, not all, see below for limitations) that are supported AspectWerkz. Such as, a rich pointcut expression language, before/after/around advice, deployment modules defined by the META-INF/aop.xml file etc.

Very high-performant

You will also get the full performance of the AspectWerkz 2 architecture.

If you are interested details of the benchmark we made (and/or run it yourself) then you can read this paper.

But in short AW Proxy is roughly:

Limitations

Since it is a proxy approach it only supports execution pointcuts and can only advise methods and constructors that is non-private and non-final. E.g not call, set, get or handler pointcuts. Advice bound to these pointcut types will simply not affect the class being proxied.

Resources

This new feature will be available in AspectWerkz 2.0 RC2 that will be available soon. Until then you can check out the sources from the CVS and build it yourself (by invoking ant dist).

There are some samples in the ./src/samples/examples/proxy dir in the distribution. These can be executed by invoking ant samples:proxy from the command line.

Enjoy.

Jonas Bonér 08 December 2004
blog comments powered by Disqus