AOP Docs: Putting the Library to Use

It's time to get your hands dirty - here's what we'll be doing to get you familiar with implementing the library in your software to leverage the benefits of AOP;

  1. Identify the cross-cutting concern.
  2. Create a sample CFC exposing a method which will act as the concerns point-cut.
  3. Create an Aspect (both an orphan UDF and a method on a new CFC).
  4. Apply the aspect at a specific join-point.
  5. Invoke the original point-cut method - watch AOP transparently do it's job.

Identifying the Cross-Cutting Concern

Seeing as how this is simply a tutorial - we'll use a simple and straight-forward twist on the ever-popular AOP logging example. But instead of logging process information to a file, we'll simply use CF's native trace() mechanism which will output trace information to the screen as long as you've enabled debugging output in the administrator.

Creating a Point-Cut

In the real world, it's likely that once you've identified a cross-cutting-concern you'll already have a code-base to which the concern applies. If you're really on top of things, you will have identified your concerns at design time. Regardless, we're working in example mode so we'll start from scratch. Create a CFC and name it MyObject.cfc, save it in a location that you'll be able to easily reference.

Creating an Aspect

If you haven't already, create a .cfm file that you can use as a scratchpad to instantiate the objects you need and to output our example results.

We're ready to create our aspect. First, we'll create a simple UDF as an aspect - we won't create a new component, yet. So crack open your scratchpad .cfm file and create an inline method. The aspect we create will have a join-point of type "before", so our aspect method must adhere to that contract (discussed previously). Your .cfm file should now look something like this;

As you can see, this aspect will simply trace log an invocation on any method to which this aspect is applied. Let's tie it all up neatly now.

Now modify your .cfm file and create an instance of MyObject. Invoke the echo() method and write the results to screen. Of course we haven't applied any aspects to anything yet, this is simply to demonstrate the results of the echo() method before any AOP'ification (yes, that's a made-up word);

Running the above script will produce output like this;

	Hi, you said Hello World
	

Our MyObject echo() method is working as expected.

Applying the Aspect

Here's where the core library components come into play. There are two components that perform the object decoration and effectively prepare our point-cut method for aspects. Each implement the Interceptor interface and expose a single method called interceptAt();

The two library implementations of this interface are located in the org.cfcommons.aop.impl package and are named;

	MethodScopeInterceptor
	ObjectScopeInterceptor
	

Each is responsible for applying aspects to a target object and method with the two different aspect types, Method Reference and Object Instance type aspects respectively. We of course are going to use the MethodScopeInterceptor as the aspect that we've created for this example is a simple UDF.

Let's go back to our scratchpad .cfm file and create an instance of this interceptor type - and apply our UDF aspect to the echo() method of MyObject;

Before you refresh the page to see the results, let's walk through the call to interceptAt(). First off, we're passing in a reference to MyObject with the "object" variable. interceptAt() simply takes that reference and decorates it with the correct behavior, it provides all of the necessary plumbing on that object in order for it to exhibit AOP behavior per our aspect. Don't worry, your object is still true to it's original contract and API and' will function exactly as it was intended. The second argument "interceptedMethod" indicates the exact point-cut that we need to Aspectify (yes, another made-up word). This is the name of the method as a string. Next the "aspectInstance" argument requires a reference to a UDF - THIS IS NOT A STRING WITH THE NAME OF THE METHOD. Notice how there are no quotes around this argument - this is an actual variable representing the method itself. The "aspectName" argument value should be an empty string for Method Scope aspects - this argument is only relevant for Object Scope aspects. Lastly, we indicate the actual join-point at which we require the aspect to take control. The only acceptable values are "before", "after", and "around". In this case, we're going to log (via trace()) this method invocation before the actual invocation occurr.

Go ahead and refresh the page, you should still see the original output - BUT, if you have debugging enabled, you should see as a part of the debug output something to the effect of the following:

	[13:52:22.271 C:\{path-to-your-scratchpad-file}.cfm @ line: 15] [29 ms (1st trace)]
		 - Invoking echo at {ts '2010-01-22 13:52:22'}.
	

Our AOP transparently did it's job by logging the invocation to the echo() method. This aspect can now be applied to any method on any object instance in the same way we applied it to MyObject's echo() method. Go ahead and play around with it - this time use the ObjectScopeInterceptor to pass in another object instance with a method that acts as the aspect - not simply a UDF.

Finally

There's a few things to keep in mind when utilizing this library to leverage AOP in your ColdFusion code;

  • Interceptor implementations do not maintain any state, in fact the interceptAt() method should be considered static - it would be wise to maintain any Interceptor instances as singletons and utilize them as such.
  • Any number of disparate aspect types (Method Scope and Object Scope) can be attached at "before" and "after" join points to any point-cut.
  • Aspects are invoked in the order in which they were attached to the join point.
  • Only one aspect can exist at the "around" join point for any point-cut.

<< Understanding Advice / Aspects and Point Cuts    Module Home >>

Quick Nav

All Modules

In Touch

Featured Module

Contribute

Download Now