Using AspectJ to Track Down Performance Issues in a Massive Legacy Project

I’ve been involved with a rather large project lately.  The code was initially written by a consulting firm, and it was written poorly:

  • Single classes reaching 15k lines
  • Code duplication everywhere
  • Very basic Java functionality reimplemented from scratch
  • Pretty much zero code gets passed the information it needs – everything reaches out to static and global variables
  • Zero unit tests (although the code is extremely hard to unit test, since everything depends on everything else)

Just to name a small fraction of the issues that were handed to us.

It’s like being a gardener – you normally add flowers, remove weeds, etc.  And you get dropped off somewhere in the middle of the Rain Forest with a list of rivers to dam, and mature redwoods to add.

It would’ve been nice if those of us tasked with completing and maintaining this project were allowed to simply start over.  But that’s been a tough sell.

So instead we’ve had to learn to navigate this mess and do what we can to improve it, all while implementing new features, and fixing bugs.

We’ve managed to improve it substantially.  However, it’s still way too slow for the poor users.  They get understandably frustrated when navigating to a small form easily takes 5-10 seconds to load.  So it’s become time to speed it up!

But where do we begin?

First, We Measure

We need to understand what’s slow.  We have to analyze the code, find spots that are redundant, and parts that are just taking way longer than they should.

Enter AOP

AOP (Aspect Oriented Programming) is fantastic for long-term gathering of performance on a production system.  It essentially allows you to weave functionality into your code base using patterns.  And specifically for performance monitoring, you can use it to start a timer before any method is called, stop the timer when the method has completed, and log the result. 

It’s also rather easy to use, if your application is configured with Spring.  Since you configure AOP inside the Spring configuration, and tell it what classes and methods to intercept.

Then, We Attack the Worst Parts

Using this we start to see a picture of what parts of the program take the longest to run.  We can then poke around inside these areas that are slow, or are called an unusually high number of times.  For example, it turns out that a “registerLogin” function was being called thousands of times from all over the place, seemingly at random.

This helps a huge amount, but there’s a problem.  Only a small fraction of the application is Spring managed.  Which is the context that AOP likes to run in.  It wouldn’t wrap around plain old Java objects.

Turns out that instead of using Spring for large sections of the application, the original consulting company had come up with their own framework that dynamically finds the appropriate class by ID and creates a new instance of it.

This framework was responsible for making some of the largest and most frequently used objects in the entire application.  We were missing so much information by not being able to automatically time these.

Programmatic AOP Functionality with Any Java Object

AspectJ provides a rather simple Factory method for wrapping an object with AOP code.

AspectJProxyFactory factory = 
    new AspectJProxyFactory( instanceOfSlowObject ) ;

factory.addAspect( MyAopAspect.class ) ;

SlowObject proxyOfSlowObject = factory.getProxy() ;

On its own, however, it defaults to returning a proxy for an interface that the passed in Object inherits.  Which can cause some problems, so we want to proxy the class.  Normally, yes, you want to deal only with interfaces if you can.  But, when left to work in that way, many of the proxies started throwing cast exceptions, so we had to change it.

factory.setProxyTargetClass( true ) ;

This was all wrapped up in a rather easy to use Utils helper class:

public final class PerformanceLoggingProxyUtils {

    private PerformanceLoggingProxyUtils(){}

    * Allows easy performance logging of Objects. It will take the 
    * Object, generate a proxy for it, and pin the performance 
    * logging Aspect to it, so that every method call (as 
    * configured in the Aspect) is timed and logged with Perf4j.
    * @param baseToWrap                                            
    * @return                                                      
    public static <T> T withPerformanceLogging( T baseToWrap ) {   

        AspectJProxyFactory factory = 
            new AspectJProxyFactory( baseToWrap ) ;

        // This tells AspectJ to proxy the Class instead of the 
        // Interface that the class implements.
        factory.setProxyTargetClass( true ) ;

        // The Aspect that is going to perform the performance 
        // logging we are wrapping.
        factory.addAspect( PerformanceLoggingAspect.class ) ;

        return factory.getProxy() ;



Which allowed us to easily hook the same AOP performance logging into the custom framework that dominated the code base. 

And now the performance data is just flowing in!

Leave a Reply

Your email address will not be published. Required fields are marked *