Friday, November 12, 2004

AOP

So all this talk of Aspect Oriented Programming going on right now. Still don't have a crystal clear picture of what it involves but I'm beginning to understand what it's about and its benefits.

We had a project in my CS class which helped me understand the potential of AOP. My prof had no clue about AOP so that was not his intent - just something I realized on my own after our discussions on the subject.

We had to create a proxy object. The client would provide a list of interfaces and implementations for the proxy object. Essentially the way it would work is that instead of having a concrete class that implements certain interfaces and has an implementation, you would only have a proxy object and tell it to dynamically create objects that implement the interfaces and have access to classes that provide an implementation for the interfaces.

    Proxy
|-----------|
|If1 | Imp1 |
|If2 | Imp2 |
|If3 | Imp3 |
|-----------|


So if you have a handle to the proxy object, you can call any of the methods on the interfaces it implements, but first you would need to cast it...

Class[] interfaces = new Class[] { Class.forName( "If1" ), Class.forName( "If2" ), Class.forName( "If3" ) };

Class[] implementations = new Class[] { Class.forName( "Imp1" ), Class.forName( "Imp2" ), Class.forName( "Imp3" ) };

Object proxy = ProxyFactory.getNewInstance( interfaces, implementations );

If1 interface1 = (If1) proxy;
interface1.someMethod1(); // 1

If2 interface2 = (If2) proxy;
interface2.someMethod2(); // 2


So the way this works is that the proxy object internally has an InvocationHandler. The InvocationHandler intercepts any calls on the proxy object. So when 1 is executed, you get to the InvocationHandler and the system tells it which method is being called (someMethod1) and on what interface (If1). So at this point, InvocationHandler will create an object of type Imp1 and actually call the method on that object. Same thing when 2 is executed. In this case, an instance of type Imp2 is created and the someMethod2 is called on it.

interface1.someMethod1() --> Proxy --> InvocationHandler --> ( new Imp1() ).someMethod1() --> Return

interface2.someMethod1() --> Proxy --> InvocationHandler --> ( new Imp2() ).someMethod2() --> Return

Basically what this provides is a level of indirection. This is possible in large part because of reflection. The most important part is that your InvocationHandler is the one calling the actual method implementation. Normally we would manually create an object of Imp1 or Imp2 and called the respective methods, but here we don't interact with them directly. So you could executed some additional code before and after the method is called. The most common example for AOP given is Logging. So we could log information before or after the method call is made.

interface1.someMethod1() --> Proxy --> InvocationHandler --> Log --> ( new Imp1() ).someMethod1() --> Log --> Return

interface2.someMethod1() --> Proxy --> InvocationHandler --> Log --> ( new Imp2() ).someMethod2() --> Log --> Return

This ability to inject your own functionality between someone else's method calls is quite interesting.

No comments: