The kinds of advise available in Spring AOP are BEFORE, AFTER, AFTER RETURNING, AFTER THROWING and AROUND. The first four are simple and get called in aspects as their name suggest. The last one ‘around’ is a different one. Well why this one is different from others is, the spring framework basically wraps the target join point(or target method) into the around advise. How is it done? The spring framework provides a ProceedingJoinPoint parameter which helps to weave the target method into around advice.
Lets take a example to show how it works. We have a bean which has a method called saveData() and we want to profile the amount of time it takes to persists the data. So we need some one to record time before and after the saveData() method is called. And here comes the ‘around’ advice for our help. We will declare a point cut for saveData() method and a around advice for this which will note down the start time, proceed with join point(our saveData method) and note down the end time once join point completes.
1. Our Simple Bean ‘MySpringAOPBean’
package com.springaoptest.beans; public interface MySpringAOPBean { public void saveData(); }
package com.springaoptest.beans; public class MySpringAOPBeanImpl implements MySpringAOPBean { @Override public void saveData() { System.out.println("[saveData]: Saving Data"); } }
2. Our Profile Service Bean
package com.springaoptest.services; import org.aspectj.lang.ProceedingJoinPoint; public interface MyProfileService { public void profileMethod(ProceedingJoinPoint joinPoint); }
package com.springaoptest.services; import org.aspectj.lang.ProceedingJoinPoint; public class MyProfileServiceImpl implements MyProfileService { @Override public void profileMethod(ProceedingJoinPoint joinPoint) { System.out.println("[profileMethod]: Started profiling method"); long startTime = System.nanoTime(); try{ joinPoint.proceed(); }catch(Throwable e){ System.out.println("Help Help Help"); } long endTime = System.nanoTime(); System.out.println("[profileMethod]: Your method took "+(endTime-startTime)+ " nano seconds to complete"); System.out.println("[profileMethod]: Ending profileing method"); } }
If you see here profileMethod() has parameter type ProceedingJoinPoint which will be injected by the framework at the run time. And how we take the advantage of it is :
i. We do what we want to do before the actual method is called. ii. Call the saveData() using ProceedingJoinPoint.proceed() iii. Do the after method operations
3. Bean wiring and AOP configuration in xml
[we call this file aoparoundbeans.xml]
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="mySpringAOPBean" class="com.springaoptest.beans.MySpringAOPBeanImpl"/> <bean id="myProfileService" class="com.springaoptest.services.MyProfileServiceImpl"/> <aop:config> <aop:aspect ref="myProfileService"> <aop:pointcut expression="execution(* com.springaoptest.beans.MySpringAOPBean.saveData(..))" id="saveDataPointCut"/> <aop:around method="profileMethod" pointcut-ref="saveDataPointCut"/> </aop:aspect> </aop:config> </beans>
4. Main Java class to call bean.saveData()
package com.springaoptest.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.springaoptest.beans.MySpringAOPBean; public class MySpringAOPAroundTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("com/springaoptest/beans/aoparoundbeans.xml"); MySpringAOPBean mySpringAOPBean = (MySpringAOPBean)context.getBean("mySpringAOPBean"); mySpringAOPBean.saveData(); } }
5. Compile and Run MySpringAOPAroundTest
OUTPUT
May 30, 2012 8:11:26 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh . . [profileMethod]: Started profiling method [saveData]: Saving Data [profileMethod]: Your method took 90794 nano seconds to complete [profileMethod]: Ending profileing method
So here you can see that our profiling method get control and it does the pre and post processing require to profile the saveData() using the around advice.
Related links : Basics of Spring AOP | Spring AOP Hands On