I’ve just thrown a quick project up on Google Code for allowing simple AOP style programming with Parsley:
The project aims to allow simple registration of AOP interceptors by registering a metatag with an interceptor.
It uses the awesome as3-commons bytecode library for proxy generation
Configuration
The aim is to have simple configuration. You activate Flapper by simply declaring AspectSupport in your parsley context:
<parsley:ContextBuilder>
<parsley:FlexConfig type="{ParsleyConfig}" />
<tag:AspectSupport>
<tag:MetatagAspectDefinition metatag="Log" aspect="{new LoggingAspect()}" />
</tag:AspectSupport>
</parsley:ContextBuilder>
In this example, I’m registering the Log
metatag with my LoggingAspect
.
Now, any class which has a method annotated with Log
will be proxied, and the LoggingAspect will get invoked before the actual method itself.
Eg:
public class Calculator
{
[Log]
public function add(a:int,b:int):int
{
return a + b;
}
}
The aspects themselves are also extremely simple, implementing an Aspect
interface.
Here’s my LoggingAspect:
public class LoggingAspect implements Aspect
{
public function intercept(pointCut:ProceedingJoinPoint):void
{
trace(pointCut.targetMember.localName + " called with params: " + pointCut.arguments.join(","));
pointCut.proceed();
var returnValueString:String = pointCut.returnValue ? pointCut.returnValue.toString() : "null";
trace(pointCut.targetMember.localName + " returned " + returnValueString );
}
}
This simply traces out the method name that was called, and the arguments that were passed in.
Usage
That’s all the configuration that’s required. Now, any time I call calculator.add()
, the aspect will trace out the call to the console window.
Note – classes that will be proxied must be decalred using Parsley’s Object tag, rather than as an instance.
Eg:
<fx:Declarations>
<!-- Don't do this -- it won't work -->
<sample:Calculator />
<!-- Instead, decalre using the Object tag -->
<parsley:Object type="{Calculator}" />
</fx:Declarations>
Usage from here is no different than with any other injected class.
Example:
[Inject]
public var calculator:Calculator;
private function addNumbers():void
{
// Results in a message being traced out "Called add with arguments: 2,3"
calculator.add(2,3)
}
The project and a demo are available to be checked out here. It’s still fairly early days, and the project hasn’t really been tested – but feel free to grab it and have a play.
Important Credit
This whole project took 2 nights to write. The main reason it was so quick and simple is because all the hard work has already been done by two awesome existing projects.
The as3-commons team have done an amazing job on the project, but also in providing thorough clear documentation.
Equally so, Jens Halm has done an outstanding job on Parsley, making the framework so easy to extend, with a solid API, and killer docs. Not to mention he’s extremely responsive in the forums. Both these projects rock.
Update:
I’ve updated this blog post to reflect the move to the Aspect interface, where previously I was using the ascommons-bytecode IInterceptor. This has made chaining Aspects easier. Note – I’m still using ascommons-bytecode underneath, but it’s now abstracted away a little more.
Nice work! Really stoked to see as3commons-bytecode getting adopted so early. Keep up the great work!
Proxying has been finished completely since the last release of v0.9.4 (which fixed proxying of methods that have …rest arguments declared). There will be some more interesting stuff before v1.0, so keep an eye on the repository 🙂
cheers!
Roland
I’m impressed with this too, great work! One question though – is there a way to apply aspects to, say, all methods in a class?
Hi Borek
Thanks for the kind words.
Regarding wiring to any method / object- not yet, but I’m working on it.
I’ve created a feature request – feel free to share your thoughts on how you’d like to see this implemented.
http://code.google.com/p/flapper-as/issues/detail?id=3
Marty
Hi Marty, thanks for your reply, I’ve left a couple of comments there.
Hey Marty,
Great work.
This AOP support you’ve developed for Parsley has come in very useful on my current project.
Cheers
Josh
Cool – glad you like it! Check out the latest from the weekend, which adds support for proxying any class / method based on a pattern, which removes the need for the metatags.
Dude, this aop support is excellent. Guys on my team will love it. OR ELSE 😀