Saturday, January 21, 2012

Spring AOP Tutorial


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>

1 comment:

  1. Thanks for the article, it's very easy to understand

    ReplyDelete