Contents
This is my second article about Spring Aspect Oriented Programming. This article will show the basics and how to use Spring AOP easily, by using some tools such Eclipse, Maven, Spring AOP version 2.5, etc.
Wait! Why Spring AOP and not full AspectJ?
“Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring beans, then Spring AOP is the right choice. If you need to advise objects not managed by the Spring container (such as domain objects typically), then you will need to use AspectJ. You will also need to use AspectJ if you wish to advise join points other than simple method executions (for example, field get or set join points, and so on).” - from http://static.springsource.org/spring/docs/2.5.x/reference/aop.html.
After reading the above, you will know the answer to the question! We just need a very simple framework to start AOP. The best choice is the popular one (so it is easier to find someone who can help us ^_^”).
Let's start on Aspect Oriented Programming! But you need to know that I'll only use Spring XML configuration – this maybe the hard way, but it's fun!
“Aspect-oriented programming entails breaking down program logic into distinct parts (so-called concerns, cohesive areas of functionality). All programming paradigms support some level of grouping and encapsulation of concerns into separate, independent entities by providing abstractions (e.g., procedures, modules, classes, methods) that can be used for implementing, abstracting, and composing these concerns. But some concerns defy these forms of implementation, and are called crosscutting concerns because they "cut across" multiple abstractions in a program.” - from http://en.wikipedia.org/wiki/Aspect-oriented_programming#Overview
Distinct parts? Abstractions, Multiple abstractions? Crosscutting concerns? Now your head hurts, and you've trouble understanding AOP – don't worry – this can be simplified:
AOP is like Triggers in programming languages such as Perl, .NET, Java and others.
That's easy, right? Can see a blurred little gray light in the AOP way?
Maybe you have learned a bit about SQL and you've heard about Procedures and Triggers:
- In SQL, you create a Trigger for a table or view.
- Your Triggers will be for a specific action (insert, update, etc...).
- And executed at a chosen time (for, after, etc.)
AOP has similar things:
- You create something called “Aspect”.
- Your “Aspect” will be executed by checked something called “Pointcut”.
- Also executed at a chosen moment (before, after, around, etc...).
This is AOP, but you need to know the AOP terms and definitions, such OO-Style (package, class, method, etc.).
As for every concept, AO-Style also has its terms that you need to know a bit about before starting.
- Concern: This is a battlefield, any interest area, any Use Case (in UML), something/some-area that interested you and that you want to change, like a classical use case as “payment”, “users managements” and many others.
- Crosscutting concern: This a concern that can affect the entire application and should be centralized in one location in code as possible, such as “authentication” or “logging”.
- Join Point: A point during the execution of a program, such as the execution of a method or the handling of an exception.
- Aspect: Is a module that encapsulates a concern. An aspect is composed of Pointcuts, advice bodies, and inter-type declarations. In some approaches, an aspect may also contain classes and methods.
- Pointcut: A predicate that matches Join Points.
- Advice: Action taken by an Aspect at a particular Join Point in a desired moment - “before”, “after”, etc.
That is not all the AO-Style terms, but just those we need for starting; for more Spring AOP terms, you can check out http://static.springsource.org/spring/docs/2.5.x/reference/aop.html.
Pointcut is a predicate that matches Join Points. This has a very similar syntax style like pattern matching (for Perl programmers) or like Regular Expressions. This predicate or expression matches, for example, a method with a certain name. Example (pointcut for all methods whose names begin with 'list'):
execution ( * adrabi.codeproject.*.GamesImpl.list*( .. ) )
All methods in the class GameImpl
that have names starting with 'list' and has any type of parameter.
/!\ Ops! I forget to tell you that Spring AOP is limited only to public methods in beans, unlike AspectJ. You don't have any problems with that, do you?
Seriously, Pointcut is an important part in Aspect. An advice can't be triggered or executed without matching a right Pointcut, or you won't get the desired results.
But, wait man! Why have you started by writing execution( )
? Can you show us a real example?
Firstly, this is a real example:
<aop:config>
<aop:pointcut id="gamesService"
expression="execution(* com.xyz.myapp.service.*.*(..))" />
</aop:config>
Secondly, in our case, execution()
is necessary. It's a pointcut type or (pointcut designator). Additionally, pointcut isn't limited to a single execution(). You can combine several of them using AND “&&”, OR “||”, and Negated “!”. Surprised?
Now it is time to prepare yourself to start Spring AOP by configuring your environment.
Finally! the real examples in action. Try to prepare a very delicious cup of coffee and come back!
You need to install Maven and SpringIDE in Eclipse by following this article: “Pivot 1.4, Spring and Hibernate is my RPG Game” - http://www.codeproject.com/KB/java/PivotSpringHibernateGame.aspx (you need to just read the environment configuration, and come back as a winner).
Now you know how to install anything in Eclipse – very nice – and you need to install Eclipse TDTD for the monitoring and views execution flows. It's not really needed, but the best way to understand is to view “how objects” interact.
Installing Eclipse TDTD
TDTD example for classes interaction
This is not hard at all. You just need to open the configuration file in your brain and change the variable “use_imagination = 0” to “use_imagination = 1” :D Just kidding.
Now, time to start coding.
After the configuration is done, we will start coding examples. For each example, we create a unique project, and we use the pointcut type “execute()
”. We will see the other types later. By using Maven, we don't need a specific configuration for every project; the same configuration can be used for all the projects.
Additionally, you need to know how to create a Maven project and add it as a Spring Project Nature (http://www.codeproject.com/KB/java/PivotSpringHibernateGame.aspx).
This is a POM configuration for all projects:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<target>1.5</target>
<source>1.5</source>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
<scope>compile</scope>
</dependency>
</dependencies>
What' do we do?
We simulate a simple CRUD application for hardwares by using:
- An interface for service called: HardwareService.java
- A class for implementing the interface called: HardwareImpl.java
- A simple class entity called: Hardware.java
- A class for creating methods for Pointcuts called: HardwareServicePointcuts.java
- And a class for executing the application called: Main.java
- Plus Spring configuration file called: application.xml
with the objective to apply three Aspects for the Hardware service (HardwareImpl.java) in advice “before”. And we study the results, and each Aspect has a unique pointcut that uses a unique method in the Hardware service pointcuts (HardwareServicePointcuts.java). The pointcut's objectives are:
- Pointcut for triggering method “
beforeAnyMethodStartedWithList
” within any method in the Hardware service, with a name beginning with 'list begin executing'. - Pointcut for triggering method “
beforeRemove
” within the method “remove
” begins executing. - Pointcut for triggering method “
beforeIfNotSaveMethod
” within any method not named “save
” in the Hardware service begins executing.
Are the objectives clear? Let's study the results and output, but before we do it, I'll paste here just the interested parts in the source:
public interface HardwareService
{
public Hardware save( Hardware hw );
public void remove( Hardware hw );
public Hardware get(int id);
public List<Hardware> listAll();
public List<Hardware> listByVendor(String vendor);
}
This is the Hardware service (HardwareService.java):
public class HardwareServicePointcuts
{
public void beforeAnyMethodStartedWithList()
{
System.out.println("*** Some methods started with 'list' has " +
"begin executing now! ***");
}
public void beforeRemove()
{
System.out.println("*** Method 'remove' has begin executing now! ***");
}
public void beforeIfNotSaveMethod()
{
System.out.println( "*** Method 'save' hasn't begin executing yet! ***" );
}
}
This is the method that will be triggered if the Pointcuts match.
<aop:config>
<aop:aspect id="anyMethodStartedWithList" ref="hardwareServicePointcuts">
<aop:before method="beforeAnyMethodStartedWithList"
pointcut="execution(* adrabi.codeproject.*.*.*.HardwareImpl.list*(..) )" />
</aop:aspect>
<aop:aspect id="MethodRemove" ref="hardwareServicePointcuts">
<aop:before method="beforeRemove"
pointcut="execution(* adrabi.codeproject.*.*.*.
HardwareImpl.remove(adrabi.*.*.*.*.Hardware) )" />
</aop:aspect>
<aop:aspect id="notMethodSave" ref="hardwareServicePointcuts">
<aop:before method="beforeIfNotSaveMethod"
pointcut="!execution(* adrabi.codeproject.*.*.*.HardwareImpl.save(..) )" />
</aop:aspect>
</aop:config>
And this is a configuration for Spring AOP. You will notice three Aspects. Each Aspect has an advice “before”, and for each Advice, there is a pointcut. Each pointcut tries to match something.
pointcut="!execution(*adrabi.codeproject.*.*.*.HardwareImpl.save(..) )"
Did you notice a negation “!” before “execution(..)
”? This confirms what I motioned in the previous chapters.
Now we profile the application main (in the Main
class, right click > in the context menu > click Profile As > Java Application):
public static void main(String[]$)
{
ApplicationContext context =
new ClassPathXmlApplicationContext("application.xml");
HardwareService hds = (HardwareService) context.getBean("hardwareService");
System.out.println("\n\n###############[ -- any method " +
"started with 'list' -- ]#################");
List<Hardware> list = hds.listAll();
for( Hardware h : list )
{
System.out.println( h );
}
System.out.println("\n\n###############[ -- method " +
"named 'remove' -- ]#################");
hds.remove( hds.get(2) );
System.out.println("\n\n###############[ -- method " +
"named 'save' -- ]#################");
hds.save( new Hardware(4, 5454477877213l, "vendor #4") );
for( Hardware h : list )
{
System.out.println( h );
}
}
After the profiling finishes successfully, we get a nice output that we compare with the class interactions:
###############[ -- any method started with 'list' -- ]#################
*** Some methods started with 'list' has begin executing now! ***
*** Method 'save' hasn't begin executing yet! ***
Hardware :: Identify [1], Serial number [1234567890254] and Vendor [vendor #1]
Hardware :: Identify [2], Serial number [6545665661545] and Vendor [vendor #2]
Hardware :: Identify [3], Serial number [1545422984548] and Vendor [vendor #3]
###############[ -- method named 'remove' -- ]#################
*** Method 'save' hasn't begin executing yet! ***
*** Method 'remove' has begin executing now! ***
*** Method 'save' hasn't begin executing yet! ***
###############[ -- method named 'save' -- ]#################
Hardware :: Identify [1], Serial number [1234567890254] and Vendor [vendor #1]
Hardware :: Identify [3], Serial number [1545422984548] and Vendor [vendor #3]
Hardware :: Identify [4], Serial number [5454477877213] and Vendor [vendor #4]
Now we open the profile report with the “class interactions”:
We compare the first Aspect “any method starting with 'list' ” and this is a part from the sequence diagram:
From the diagram, we conclude that matches are 100.1 % output results. You see two methods “beforeAnyMethodStartedWithList
” and “beforeIfNotSaveMethod
” has executed before the method “listAll
” in the HardwareImpl
class.
Remember, we've created the Aspect for the bean/class HardwareImpl
(HardwareImpl.java).
/!\ Ops! I forgotto tell you, the Spring triggers and/or executes aspects by the order in the configuration file.
If we've the configuration below, the results will be different from the last profiling. Try it and you will see the difference:
<aop:config>
<aop:aspect id="MethodRemove" ref="hardwareServicePointcuts">
<aop:before method="beforeRemove"
pointcut="execution(* adrabi.codeproject.*.*.*.
HardwareImpl.remove(adrabi.*.*.*.*.Hardware) )" />
</aop:aspect>
<aop:aspect id="notMethodSave" ref="hardwareServicePointcuts">
<aop:before method="beforeIfNotSaveMethod"
pointcut="!execution(* adrabi.codeproject.*.*.*.HardwareImpl.save(..) )" />
</aop:aspect>
<aop:aspect id="anyMethodStartedWithList" ref="hardwareServicePointcuts">
<aop:before method="beforeAnyMethodStartedWithList"
pointcut="execution(* adrabi.codeproject.*.*.*.HardwareImpl.list*(..) )" />
</aop:aspect>
</aop:config>
Maybe, the rest is fine and clear? Ijust want to clarify why we've the aspect for the method named 'remove' twice:
###############[ -- method named 'remove' -- ]#################
*** Method 'save' hasn't begin executing yet! ***
*** Method 'remove' has begin executing now! ***
*** Method 'save' hasn't begin executing yet! ***
As you can see in the Main
class:
System.out.println("\n\n###############[ -- method " +
"named 'remove' -- ]#################");
hds.remove( hds.get(2) );
Just try to read this code carefully and slowly: “hds.remove( hds.get(2) );
”. We've two methods here: first “get
”, and second “remove
”. “get
” is triggered for aspect n°3 because its name is different from “save
” and “remove
”.
The next advice is the opposite of before, and we call it “after
”.
What do we do here?
We simulate a simple authentication system by using:
- An interface for service called: AuthenticationService.java
- A class for implementing the interface called: AuthenticationImpl.java
- A class for creating the methods for the Pointcuts called: AuthenticationServicePointcuts.java
- And a class for executing the application called: Main.java
- Plus the Spring configuration file called: application.xml
With objectives similar to the advice “before”, we've just two Aspects and two Pointcuts:
- Pointcut for triggering method “
afterUsernameOrPassword
” within the method “userName
” or “password
” has finished executing. - Pointcut for triggering method “
afterLogout
” within any method “logout
” in Authentication service has finished executing.
We do some steps as advice “before”.
public interface AuthenticationService
{
public void userName(String userName);
public void password(String password);
public boolean login();
public boolean logout();
}
This is the Authentication service:
public class AuthenticationServicePointcuts
{
public void afterUsernameOrPassword()
{
System.out.println("*** username or password method has exected ***");
}
public void afterLogout()
{
System.out.println( "*** you've logout now! see you later, bye! ***" );
}
}
This is a method that will be triggered if Pointcuts match:
<aop:config>
<aop:pointcut id="p_usernameOrPassword"
expression="execution(* userName(..)) or execution(* password(..))" />
<aop:pointcut id="p_logout" expression="execution(* logout())" />
<aop:aspect id="afterUsernameOrPassword" ref="authServicePointcuts">
<aop:after method="afterUsernameOrPassword" pointcut-ref="p_usernameOrPassword"/>
</aop:aspect>
<aop:aspect id="afterLogout" ref="authServicePointcuts">
<aop:after method="afterLogout" pointcut-ref="p_logout"/>
</aop:aspect>
</aop:config>
You can see two things have changed:
- Firstly, we've created a separated Pointcut.
- Secondly, in advice “
after
”, we don't use the parameter “pointcut” as advice “before” but has replaced it with “pointcut-ref”.
Also, you will notice in pointcut n°1 “usernameOrPassword
”, I've used “or ”:
expression="execution(* userName(..)) or execution(* password(..))"
Spring AOP support both expressions “OR” and “||”; you've a choice.
We profile the main application:
public static void main(String[]$)
{
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
AuthenticationService auth = (AuthenticationService)context.getBean("authService");
auth.userName("adrabi");
auth.password("no-password");
System.out.println( "Login results is : " + auth.login());
System.out.println( "Logout results is : " + auth.logout());
}
And we get a nice output:
*** username or password method has exected ***
*** username or password method has exected ***
Login results is : true
*** you've logout now! see you later, bye! ***
Logout results is : true
Now, we open the profile report with “UML 2 class interactions” and we can see this part from the sequence diagram:
Perfect, really similar to the output. We can see in both methods “userName
” and “password
”, the method “afterUsernameOrPassword” was triggered after execution finishes.
We jump to the last advice but not the least.
What do we do here?
We simulate a simple serial system crack by using:
- An interface for the service called: SerialService.java
- A class for implementing the interface called: SerialImpl.java
- A class for creating methods for Pointcuts called: SerialServicePointcuts.java
- And a class for executing the application called: Main.java
- Plus a Spring configuration file called: application.xml
With objectives similar to the advice “before”, we use two Pointcuts for cracking a serial number system:
- Pointcut for triggering the method “
aroundCheckSerialNumber
” to replace the method “checkSerialNumber
”. - Pointcut for triggering the method “
aroundSendHasActived
” to replace the method “sendSerialHasActived
”.
We do some steps as in the advice “before”.
public interface SerialService
{
public boolean checkSerialNumber(String serial);
public void sendSerialHasActived();
}
This is the Serial service:
public class SerialServicePointcuts
{
public boolean aroundCheckSerialNumber( ProceedingJoinPoint joinPoint )
{
System.out.println( "*** The method [" + joinPoint.getSignature().getName() +
"] has been cracked ^_^ ***" );
return true;
}
public void aroundSendHasActived(ProceedingJoinPoint joinPoint)
{
System.out.println( "*** The method [" +
joinPoint.getSignature().getName() +
"] has been cracked ^_^ ***" );
}
}
This is a method that will be triggered if the Pointcuts match:
<aop:config>
<aop:aspect id="aroundCheckSerialNumber" ref="serialServicePointcuts">
<aop:around method="aroundCheckSerialNumber"
pointcut="execution(* checkSerialNumber(..))"/>
</aop:aspect>
<aop:aspect id="aroundSendHasActived" ref="serialServicePointcuts">
<aop:around method="aroundSendHasActived"
pointcut="execution(* sendSerialHasActived(..))"/>
</aop:aspect>
</aop:config>
This is our evil Spring AOP configuration ^_^ to crack the serial number system and to stop the serial number being sent to the vendor.
You can also comment it and see what results can surprise you.
Now we profile the Main
class:
public static void main(String[]$)
{
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
SerialService serial = (SerialService) context.getBean("serialService");
if( serial.checkSerialNumber(null) )
{
serial.sendSerialHasActived();
}
}
And we get a very nice output:
*** The method [checkSerialNumber] has been cracked ^_^ ***
*** The method [sendSerialHasActived] has been cracked ^_^ ***
Hurry up to view the class interactions:
You can see in the sequence diagram that the methods “checkSerialNumber
” and “sendSerialHasActived
” have been replaced by “aroundCheckSerialNumber
” and “aroundSendHasActived
”. That is cool, right? Personally, the “around” advice is my preferred one.
I hope you've enjoyed the classical advises “before”, “after” and “around”.
I'm so tired, I can't create more projects for the last two advises “after returning” and “after throwing”. You now know how to create your own Aspects and now you know about Spring AOP too. I'll just introduce them:
- “after returning” advice: Advice to be triggered/executed after a join point completes normally: for example, if a method returns without throwing an exception.
- “after throwing” advice: Advice to be triggered/executed if a method exits by throwing an exception.
It's easy to understand: “after returning” for after successful “return” in any method, and “after throwing” for after any exception in a method that causes the method to exit. But, where is the place for an “after” advice between them? “after” advice is a full finished method; in other words:
“after” advice = “after returning” advice + “after throwing” advice.
Now you can create your own examples for them by using one of the preview projects; refer to the documentation.
We never introduced parameters in AOP so far, and this is the right time to discuss a bit about them. Can we pass parameters from a JoinPoint to methods triggered/executed? Yeah, we can do it easily! I'll show you two methods for passing parameters.
Do we pass them using Spring XML configuration? Normally, we use the Spring XML configuration. What do we do?
We simulate a simple search engine for the Manga and Anime episodes and save the queries by using:
- An interface for the service called: SearchService.java
- A class for implementing the interface called: SearchImpl.java
- A class for creating methods for Pointcuts called: SearchServicePointcuts.java
- And a class for executing the application called: Main.java
- Plus a Spring configuration file called: application.xml
To pass parameters form JoinPoints to the triggered/executed method with two Pointcuts linked to the advice “after”:
- Pointcut for triggering method “
afterBingSearch
” within the method “bingSearch
” has finished executing. - Pointcut for triggering method “
afterGoogleSearch
” within any method “googleSearch
” in the Authentication service has finished executing.
public interface SearchService
{
public void bingSearch(String query, String cookie);
public void googleSearch(String query, String cookie, String userId);
}
This is the Search service source code:
public void afterBingSearch(JoinPoint jp)
{
System.out.println( "*** Save Bing search : [query : " + jp.getArgs()[0] +
", cookie : " + jp.getArgs()[1] + "] ***" );
}
public void afterGoogleSearch(String query, String cookie, String userId)
{
System.out.println( "*** Save Bing search : [query : " + query +
", cookie : " + cookie + ", userid : " + userId + "] ***" );
}
This is pointcut's source code:
<aop:config>
<aop:aspect id="afterBingSearch" ref="seachServicePointcuts">
<aop:after method="afterBingSearch" pointcut="execution(* bingSearch(..))"/>
</aop:aspect>
<aop:aspect id="afterGoogleSearch" ref="seachServicePointcuts">
<aop:after method="afterGoogleSearch"
pointcut="execution(* googleSearch(..)) and args(query,cookie,userId)"/>
</aop:aspect>
</aop:config>
We try to pass parameters in two ways:
- Firstly, by using the “
bingSearch
” method parameter type “JoinPoint” - Secondly, by binding parameters with
args(..)
in the “googleSearch
” method
Without profiling this time, we just need to run our Main
class:
public static void main(String[] $)
{
ApplicationContext context = new ClassPathXmlApplicationContext(
"application.xml");
SearchService search = (SearchService) context.getBean("searchService");
search.bingSearch("ONE PIECE", "some-cookie");
search.googleSearch("Bleach", "some-cookie", "no-userId");
}
And finally, we get a nice output and you can see that the parameters has really been passed from the JoinPoints to the triggered methods.
One Piece 452
One Piece 451
*** Save Bing search : [query : ONE PIECE, cookie : some-cookie] ***
Bleach Episode 271
Bleach Episode 270
*** Save Bing search : [query : Bleach, cookie : some-cookie, userid : no-userId] ***
I'll finish this article by showing you other Pointcut types.
Here is the rest of the Pointcuts list that can you use in the XML configuration:
- within: Limits matching join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP).
- this: limits matching join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
- target: limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
The objective of this article is to show you how to use Spring AOP and let you familiarize it. Spring AOP can also use “annotations” and support AspectJ. It's not limited to XML configuration. I just mean to use XML only.
- AOP is just triggers.
- Spring AOP can use five types for advises (before, after, around, after returning, and after throwing).
- Spring AOP is not limited to XML configuration.
I will let you discover Spring AOP annotations by yourself. Thank you for passionately reading my article, and thank you for any corrections and suggestions.