We have been modularizing our applications to achieve what is called as separation of "concerns." We created a security module, logging module, persistence module and many more modules. What were we trying to achieve? Answer is “Separation of Concerns”, but were we able to do so? Answer is NO. Though we created these different modules, we still have to use them together in our code. We still have to invoke the API’s provided by these modules in our client code. Example:
Public void someOperation(, , …){
.. Ensure authorization (user)
.. Ensure Thread Safety
.. Ensure cache is updated
.. Log start of operation
...- > perform the core operation
.. Log end of operation
.. unlock the object
}
This is what we call as code tangling. Secondly, call to the module “Ensure authorization (user)” will be scattered all over the place where we need authorization. So, what is the solution? Dynamic proxy, EJB 3 interceptors or AOP? I guess I don’t have the right answer [we’ll discuss it later], but anyways let us see what AOP has to offer.
AOP is just the methodology and AspecJ is one of its implementations, e.g. Java is one of the implementations of OOP. Also, AspectJ is aspect-oriented extension to Java [every valid java program is a valid AspectJ program.] Weaver is the component which applies the weaving rules to the core business logic to form the final system. This process is called as weaving. So, bottom line is, we create the business core concerns using Java classes, crosscutting concerns using Aspect and finally Weaver [AspectJ compiler in our case] weaves the crosscutting functionality to the core modules and gives the executable which can run on any JVM. UFFF, that was not so easy. It’s not all, we still have to learn the dialect used in this area.
Join Point: It is an identifiable point in the execution of a program, e.g. method call.
Pointcut: is a program construct that selects join points and also collects the context at those points. E.g. a methods call with the methods context, like target object and its arguments. Pointcuts are weaving rules and Join points are the situation satisfying those rules. Example will make it more clear, I know.
Advice: a code to be executed at a join point that has been selected by a Pointcut. It can be executed before, after or around the join point.
Introduction: [we will leave it for a while.] we have to come to the point ASAP, no?
Aspect: is a central unit of AspectJ, as class is the central unit of Java. It contains code that expresses weaving rules, advice, introductions. I think, example is the best way to explain here.
Let’s create the business classes first and then we will apply our crosscutting concerns over it. You will notice that we will not have to change any code in those business classes.
package com.farwaha;
interface Animal {
public void makeSound(String name, String sound);
public void makeSound(String sound);
}
//Animal Type
class Dog implements Animal {
public void makeSound(String name, String sound) {
System.out.println("Name:" + name + ", Sound: " + sound);
}
public void makeSound(String sound) {
System.out.println("Sound: " + sound);
}
}
//main
public class AOPTest {
public static void main(String[] args) {
Animal animal = new Dog();
animal.makeSound("Moti", "GRRRRRR");
animal.makeSound("THIS IS ANIMAL SOUND");
}
}
-----------------------------------OUTPUT----------------------------------------
Name:Moti, Sound: GRRRRRR
Sound: THIS IS ANIMAL SOUND
----------------------------------------------------------------------------------
Now, let’s create a Logging and Greeting aspect. Logging aspect will log execution of each method call to Animal and Greeting aspect will greet the Animal who has name.
package com.farwaha;
aspect LoggerAspect {
pointcut logMessage()
: call (* Animal.makeSound(..));
void around() : logMessage(){
System.out.println("[Log]: ... start");
proceed(); // if I comment out, the method will not even execute
System.out.println("[\\Log]: ... end");
}
}
public aspect GreetingAspect {
pointcut greetAnimal(String name)
: call (* Animal.makeSound(String , String ))
&& args (name, String);
void around(String name) : greetAnimal(name){
proceed("MR. " + name);
}
}
Compile all the files together with AspectJ compiler (ajc) and run it. Below is the output:
-----------------------------OUTPUT----------------------------------
[Log]: ... start
Name:MR. Moti, Sound: GRRRRRR
[\Log]: ... end
[Log]: ... start
Sound: THIS IS ANIMAL SOUND
[\Log]: ... end
----------------------------------------------------------------------
Let me talk about LoggerAspect. This aspects defines pointcut which results in returning join points. Let me explain, by using the below code,
pointcut logMessage()
: call (* Animal.makeSound(..));
we defined a join point at every method of Animal type which is like makeSound. We do not care what type of arguments it has [(..) expresses that] and we don’t care what is its return value [* before Animal expresses that.] Now, for every join point this pointcut returns, we want to log a message around it. Below code is self explanatory.
void around() : logMessage(){
System.out.println("[Log]: ... start");
proceed(); // if I comment out, the method will not even execute
System.out.println("[\\Log]: ... end");
}
BTW, we are done with this small exercise to start with AOP, I should rather say AspectJ. Did you notice the GreetingAspect and the way it has defined its pointcut? I think, learning how to define pointcuts in your Aspect will be the hard part.