CSC/ECE 517 Fall 2009/wiki2 9 km
What is Aspect-Oriented Programming
AOP is a programming paradigm in which the model can be dynamically modified to pefectly satisfy the growing/new requirements of a system. It complements object oriented programming by allowing the separation of cross-cutting concerns, thus modularizing them. AOP allows the developer to dynamically modify the static object oriented model to create a system that can grow and adapt to new requirements and expectations. So basically AOP is all about managing the common functionalities which span across the whole application (hence the term cross-cutting) so that it is not embedded within the business logic. It's very helpful in development of applications which change drastically during their lifecycle.
Few examples of where we can make use of AOP are:
- logging
- managing security
- transaction management
We can easily see here that these concerns are cross-cutting, meaning that they are used 'horizontally' across various points in the system.
Why do we need Aspect-Oriented Programming
To the uninitiated, AOP may seem to be something which can easily be done by Object Oriented Programming ! Infact this is true to some extent. Everything that can be done using AOP can also be done without it by just adding more code. A simple example of how AOP works is as follows: Assume you have a graphical class with many "set...()" methods. After each set method, the data of the graphics changed, thus the graphics changed and thus the graphics need to be updated on screen. Assume that to repaint the graphics you must call
"Display.update()".
The classical approach towards this would be to add more code. At the end of each set method you would write
void set...(...) { ..... ..... Display.update(); }
Now, if we have a few set() methods then we are fine and we can do this easily. But what if we have a huge system, and say we have hundreds of set() methods ! Two problems arising here are: 1) We would have to add the line Display.update(); in all these places 2) We would have to remember to add this line to any new set() methods that we create. If we forget, we just introduced a bug ! With AOP, we can shunt the responsibilty of 'remembering' to 'update the display' [executing Display.update();] whenever set() function is executed by writing an aspect
after() : set() { Display.update(); }
So instead of writing the update code yourself, you just tell the system that after a set() pointcut has been reached, it must run this code and it will run this code. No need to update 200 methods, no need to make sure you don't forget to add this code on a new set-method.
Additionally, we also need to write a pointcut:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
which basically means that if a method is named "set*" (* means any name might follow after set), regardless of what the method returns (first asterisk) or what parameters it takes (third asterisk) and it is a method of MyGraphicsClass and this class is part of the package "com.company.*", then this is a set() pointcut. And our first code says "after running any method that is a set pointcut, run the following code".
So we see that OOP has shown its strength when it comes to modeling common behavior. However OOP does not adequately address behaviors that span over many -- often unrelated -- modules. In contrast, AOP methodology fills this void.
Separation of concerns
Joint point model
The most important design feature of any Aspect Oriented language is it's Joint Point Model. The joint point model lays out the common frame of reference using which the dynamic structure of crosscutting concerns is defined. The vital aspects of this model are:
- joint points
These are the well defined points in the execution of the program. Some of the common joint points are method call and method execution, constructor call and constructor execution, field reference and field set, Handler execution , Advice execution, Object pre initialization and initialization
public class Test{ public static void main(String[] args) { Point pt1 = new Point(0,0); =======> constructor call pt1.incrXY(3,6); =======> Method call public class Point { private int x; private int y; public Point(int x, int y) { =======> Constructor execution this.x = x; =======> Field set this.y = y; } public void incrXY(int dx, int dy){ =======> Method execution x=+dx; y=+dy; } } }
- Pointcuts
Pointcuts are used to pick jointpoints which fall under certain description. For example:
call(void shape.calculate*(..))
The above pickpoint is used to select those join points which are a call to a void method defined on shape whose name begins with "calculate" regardless of the method's parameters.
Pointcuts can also be used to find join points based on whether they occur in the dynamic context of other join points.
pointcut set(): call(void Shape.setX(int)) || call(void Shape.setY(int)) find(set())
So this picks out each join point that occurs in the dynamic context of the join points picked out by set(), our named pointcut defined above. So this picks out each join points that occurs between when a move method is called and when it returns.