Spring AOP Tutorial
OOP vs. AOP
Just like OOP which is widely used to design application by modularizing core business functionalities of the application into objects AOP is used to modularize the cross-cutting concerns of the application into aspects. From OOP perspective one application system is consisted of many objects and each object encapsulates some core functionality of the system. But apart from these core business functionalities in the objects there are still non core functionalities in one system. These functionalities or requirements cannot easily be represented in objects because these such as logging, security or transaction management are scattered in various objects. If these functionalities are represented in objects there will be lots of duplicates of the codes spread in the objects. An elegant representation of these scattered or cross-cutting functionalities or concerns is needed and thus here comes AOP. AOP provides another perspective to the application system. In AOP these cross-cutting concerns are represented as aspects and then the aspects are applied to the objects or objects are advised with the aspects. OOP and AOP are complimented each other.
Benefits of Using AOP
With AOP the cross-cutting concerns can be modularized into aspects. Now the codes that implement the cross-cutting concerns are in one place: aspect. And aspect can be applied to any place where these concerns are needed. The core business objects just need to have the codes for primary business logic. All the codes of one application are better organized.
There are several ways to implement Spring AOP.
1.
One way is to create the aspect from a POJO by
implementing some AOP advice interfaces.
These interfaces are:
org.springframework.aop.MethodBeforeAdvice
org.springframework.aop.AfterReturningAdvice
org.springframework.aop.ThrowsAdvice
|
public class LoggingAdvice implements
MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
public
void before(Method method, Object[] os, Object o) throws Throwable {
System.out.println("LoggingAdvice before is invoked.");
}
public
void afterReturning(Object o, Method method, Object[] os, Object o1) throws
Throwable {
System.out.println("LoggingAdvice afterReturning is
invoked.");
}
public
void afterThrowing(Exception ex) {
System.out.println("LoggingAdvice afterThrowing is
invoked.");
}
}
|
Advice defines what (printing some message here)
and when (before the method invocation, after method invocation and etc.) to do
in an aspect. Further we need to specify
where this advice will be applied to.
That is: which method is the advice applied to. These are the works of pointcut which defines
a set of joint points where the advice is applied to.
<bean id="loggingAdvisor"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice"
ref="loggingAdvice"/>
<property name="pointcut"
ref="loggingPointcut"/>
</bean>
<bean
id="loggingPointcut"
class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property
name="expression" value="execution(* *.add*(..))"/>
</bean>
<bean id="loggingAdvice"
class="com.toic.spring3.cert.aop.LoggingAdvice"/>
|
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
|
2.
Another
way of creation of aspect is to use @AspectJ annotation with POJO when using
Java 5 or higher.
In
this way a POJO can be defined as an aspect using some annotations such as
@AspectJ, @Before, @After and etc.
@Aspect
public class
LoggingAspect {
@Before("execution(*
com.toic.spring3.aop.demo.ResourceServiceImpl.addResource(..))")
public void logBefore(JoinPoint
joinPoint) {
System.out.println("logBefore()
is running!");
System.out.println("hijacked :
" + joinPoint.getSignature().getName());
System.out.println();
}
@After("execution(* com.toic.spring3.aop.demo.ResourceServiceImpl.addResource(..))")
public void logAfter(JoinPoint joinPoint)
{
System.out.println("logAfter()
is running!");
System.out.println("hijacked :
" + joinPoint.getSignature().getName());
System.out.println();
}
@AfterReturning(
pointcut = "execution(*
com.toic.spring3.aop.demo.ResourceServiceImpl.addResource(..))",
returning= "result")
public void logAfterReturning(JoinPoint
joinPoint, Object result) {
System.out.println("logAfterReturning()
is running!");
System.out.println("hijacked :
" + joinPoint.getSignature().getName());
System.out.println("Method
returned value is : " + result);
System.out.println();
}
@AfterThrowing(
pointcut = "execution(*
com.toic.spring3.aop.demo.ResourceServiceImpl.addResourcceThrowException(..))",
throwing= "error")
public void logAfterThrowing(JoinPoint
joinPoint, Throwable error) {
System.out.println("logAfterThrowing()
is running!");
System.out.println("hijacked :
" + joinPoint.getSignature().getName());
System.out.println("Exception :
" + error);
System.out.println();
}
@Around("execution(*
com.toic.spring3.aop.demo.ResourceServiceImpl.addResource(..))")
public void logAround(ProceedingJoinPoint
joinPoint) throws Throwable {
System.out.println("logAround()
is running!");
System.out.println("hijacked
method : " + joinPoint.getSignature().getName());
System.out.println("hijacked
arguments : " + Arrays.toString(joinPoint.getArgs()));
System.out.println("Around
before is running!");
System.out.println();
joinPoint.proceed();
//continue on the intercepted method
System.out.println("Around
after is running!");
System.out.println();
}
|
<aop:aspectj-autoproxy />
<bean id="customerBo"
class="com.toic.spring3.aop.demo.ResourceServiceImpl" />
<!-- Aspect -->
<bean id="logAspect" class="com.toic.spring3.aop.demo.LoggingAspect"
/>
|
3.
There is another way to create aspect. Spring provides schema-based AOP support so
if you prefer to use XML configuration instead of annotations. You can choose this way. One of the greatest advantage of this ways is
that you can turn any POJO into an aspect.
This POJO needs no special interfaces or annotations.
public class LoggingAspect {
public void
logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running!");
System.out.println("hijacked : " +
joinPoint.getSignature().getName());
System.out.println();
}
public void logAfter(JoinPoint
joinPoint) {
System.out.println("logAfter() is running!");
System.out.println("hijacked : " +
joinPoint.getSignature().getName());
System.out.println();
}
}
|
In the XML configuration you can define an aspect
from the POJO using Spring AOP configuration elements. In the below example under
<aop:config> there is one aspect whose id is aspectLogging defined.
<aop:aspectj-autoproxy />
<bean id="resourceService"
class="com.toic.spring3.aop.demo.ResourceServiceImpl" />
<!—POJO class -->
<bean id="logAspect"
class="com.toic.spring3.aop.demo.LoggingAspect" />
<aop:config>
<aop:aspect
id="aspectLogging" ref="logAspect" >
<aop:pointcut
id="pointCutBefore"
expression="execution(*
com.toic.spring3.aop.demo.ResourceServiceImpl.addResource(..))" />
<aop:before method="logBefore"
pointcut-ref="pointCutBefore" />
<aop:pointcut
id="pointCutAfter"
expression="execution(*
com.toic.spring3.aop.demo.ResourceServiceImpl.addResource(..))" />
<aop:after
method="logAfter"
pointcut-ref="pointCutAfter" />
</aop:aspect>
</aop:config>
|