Spring @Aspect Annotation

@AspectJ refers to a style of declaring aspects as regular Java classes annotated with Java 5 annotations. The @AspectJ style was introduced by the AspectJ project as part of the AspectJ 5 release. Spring 2.0 interprets the same annotations as AspectJ 5, using a library supplied by AspectJ for pointcut parsing and matching. The AOP runtime is still pure Spring AOP though, and there is no dependency on the AspectJ compiler or weaver.

The @AspectJ support is enabled by including the following element inside your spring configuration:

<aop:aspectj-autoproxy/>

You also need to add following libraries on class path
  • aspectjrt.jar
  • aspectjweaver.jar
  • aspectj.jar

Declaring an aspect

With the @AspectJ support enabled, any bean defined in your application context with a class that is an @AspectJ aspect (has the @Aspect annotation) will be automatically detected by Spring and used to configure Spring AOP. The following example shows the minimal definition required for a logging aspect:

package com.dineshonjava.sdnext.aop.aspect;

import org.aspectj.lang.annotation.Aspect;
@Aspect
public class LoggingAspect
{
 //....
}
They will be configured in XML like any other bean as follows:
<bean class="com.dineshonjava.sdnext.aop.aspect.LoggingAspect" id="logAspect">
 <!-- configure properties of aspect here as normal -->
</bean>

Declaring a pointcut

Spring AOP only supports method execution join points for Spring beans, so you can think of a pointcut as matching the execution of methods on Spring beans.
A pointcut helps in determining the join points (ie methods) of interest to be executed with different advices. While working with @AspectJ based configuration, pointcut declaration has two parts:
  • A pointcut expression that determines exactly which method executions we are interested in.
  • A pointcut signature comprising a name and any number of parameters. The actual body of the method is irrelevant and in fact should be empty.
package com.dineshonjava.sdnext.aop.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class LoggingAspect
{
   @Pointcut("execution(* com.dineshonjava.sdnext.aop.emp.Employee.addEmployee(..))")
   public void addEmployee(){}
}
The following example defines a pointcut named 'businessService' that will match the execution of every method available in the classes under the package com.dineshonjava.sdnext.aop.aspect.service:
import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.dineshonjava.sdnext.aop.aspect.service.*.*(..))") // expression 
private void businessService() {}  // signature

Combining pointcut expressions

Pointcut expressions can be combined using '&&', '||' and '!'. It is also possible to refer to pointcut expressions by name. The following example shows three pointcut expressions: anyPublicOperation (which matches if a method execution join point represents the execution of any public method); inTrading (which matches if a method execution is in the trading module), and tradingOperation (which matches if a method execution represents any public method in the trading module).
@Pointcut("execution(public * *(..))")
    private void anyPublicOperation() {}
    
    @Pointcut("within(com.dineshonjava.sdnext.aop.aspect.trading..*)")
    private void inTrading() {}
    
    @Pointcut("anyPublicOperation() && inTrading()")
    private void tradingOperation() {}

Sharing common pointcut definitions

When working with enterprise applications, you often want to refer to modules of the application and particular sets of operations from within several aspects. We recommend defining a "SystemArchitecture" aspect that captures common pointcut expressions for this purpose. A typical such aspect would look as follows:
package com.dineshonjava.sdnext.aop.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SystemArchitecture {

  /**
   * A join point is in the web layer if the method is defined
   * in a type in the com.dineshonjava.sdnext.aop.aspect.web package or any sub-package
   * under that.
   */
  @Pointcut("within(com.dineshonjava.sdnext.aop.aspect.web..*)")
  public void inWebLayer() {}

  /**
   * A join point is in the service layer if the method is defined
   * in a type in the com.dineshonjava.sdnext.aop.aspect.service package or any sub-package
   * under that.
   */
  @Pointcut("within(com.dineshonjava.sdnext.aop.aspect.service..*)")
  public void inServiceLayer() {}

  /**
   * A join point is in the data access layer if the method is defined
   * in a type in the com.dineshonjava.sdnext.aop.aspect.dao package or any sub-package
   * under that.
   */
  @Pointcut("within(com.dineshonjava.sdnext.aop.aspect.dao..*)")
  public void inDataAccessLayer() {}

  /**
   * A business service is the execution of any method defined on a service
   * interface. This definition assumes that interfaces are placed in the
   * "service" package, and that implementation types are in sub-packages.
   * 
   * If you group service interfaces by functional area (for example, 
   * in packages com.dineshonjava.sdnext.aop.aspect.abc.service and   com.dineshonjava.sdnext.aop.aspect.def.service) then
   * the pointcut expression "execution(* com.dineshonjava.sdnext.aop.aspect..service.*.*(..))"
   * could be used instead.
   *
   * Alternatively, you can write the expression using the 'bean'
   * PCD, like so "bean(*Service)". (This assumes that you have
   * named your Spring service beans in a consistent fashion.)
   */
  @Pointcut("execution(* com.dineshonjava.sdnext.aop.aspect.service.*.*(..))")
  public void businessService() {}
  
  /**
   * A data access operation is the execution of any method defined on a 
   * dao interface. This definition assumes that interfaces are placed in the
   * "dao" package, and that implementation types are in sub-packages.
   */
  @Pointcut("execution(* com.dineshonjava.sdnext.aop.aspect.dao.*.*(..))")
  public void dataAccessOperation() {}

}
The pointcuts defined in such an aspect can be referred to anywhere that you need a pointcut expression. For example, to make the service layer transactional, you could write:
<aop:config>
  <aop:advisor advice-ref="tx-advice" pointcut="com.dineshonjava.sdnext.aop.aspect.SystemArchitecture.businessService()">
</aop:advisor></aop:config>

<tx:advice id="tx-advice">
  <tx:attributes>
    <tx:method name="*" propagation="REQUIRED">
  </tx:method></tx:attributes>
</tx:advice>

Declaring advices

You can declare any of the five advices using @{ADVICE-NAME} annotations as given below.
  1. @Before – Run before the method execution
  2. @After – Run after the method returned a result
  3. @AfterReturning – Run after the method returned a result, intercept the returned result as well.
  4. @AfterThrowing – Run after the method throws an exception
  5. @Around – Run around the method execution, combine all three advices above.
@Before("businessService()")
public void doBeforeTask(){
 ...
}

@After("businessService()")
public void doAfterTask(){
 ...
}

@AfterReturning(pointcut = "businessService()", returning="retVal")
public void doAfterReturnningTask(Object retVal){
  // you can intercept retVal here.
  ...
}

@AfterThrowing(pointcut = "businessService()", throwing="ex")
public void doAfterThrowingTask(Exception ex){
  // you can intercept thrown exception here.
  ...
}

@Around("businessService()")
public void doAroundTask(){
 ...
}

You can define you pointcut inline for any of the advices. Below is an example to define inline pointcut for before advice:
@Before("execution(* com.dineshonjava.sdnext.aop.aspect.service.*.*(..))")
public doBeforeTask(){
 ...
}



No comments:

Post a Comment