Friday, May 14, 2010

AOP with Spring.Net

AOP - Aspect Oriented Programming, coined by Xerox long time ago, shines again lately. Because it is a way to separate cross-cutting concerns such as Cache, Log, Performance Monitoring from the business process in a non-invasive way.

This led me to think about abstraction - by making a level higher abstraction, we get more valuable information to use, as levels of differentiation in Calculus.

In a OO world, AOP is all about defining scheme to apply certain functionality onto classes or methods that has something in common. To me, it is a level higher of abstraction on top of classes and methods that, in turn, are abstraction of the real world.

Spring.Net AOP called the functionality advices. To be able to be adviced, a class has to implement ICommand:

public interface ICommand
{
object Execute(object context);
}

public class ServiceCommand : ICommand
{
public object Execute(object context)
{
Console.Out.WriteLine("Service implementation : [{0}]", context);
return null;
}
}

Then we define an advice,

public class ConsoleLoggingAroundAdvice : IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
Console.Out.WriteLine("Advice executing; calling the advised method...");
object returnValue = invocation.Proceed();
Console.Out.WriteLine("Advice executed; advised method returned " + returnValue);
return returnValue;
}
}

Now we need define relationship between an Advice and an advicible target, once a method in the target class get executed, designated advice is applied.

ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingAroundAdvice());
ICommand command = (ICommand)factory.GetProxy();
command.Execute("This is the argument");

Spring.Net simply wraps up a method call with Reflection feature and tweaks around. Because ProxyFactory returns with ICommand, advicible targes have to implement the interface. This is obviously a limitation, as thus existing normal classes are not advicible. Spring.Net promised to change in future version.

In practice, of course, declarative and through configuration is prefered.

<object id="consoleLoggingAroundAdvice" type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
<object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="target">
<object id="myServiceObjectTarget" type="Spring.Examples.AopQuickStart.ServiceCommand"/>
</property>
<property name="interceptorNames">
<list>
<value>consoleLoggingAroundAdvice</value>
</list>
</property>
</object>

Above configuration just says the mapping between advices and targets in a different way. Spring.Net now knows everything needed. What we need to do is run the adviced method to check if it is really take the advice.

ICommand command = (ICommand) ctx["myServiceObject"];
command.Execute();


Ref:
1. http://www.springframework.net/doc-latest/reference/html/aop-quickstart.html#aop-quickstart-introduction

No comments: