Monday, January 25, 2010

Spring AOP with annotation

Aspect
Combination of advice and pointcuts.
Advice
The implementation of functionality that will be applied.
Pointcut
A rule for matching the parts of the object model that the functionality will be applied to.


Enable annotation

<aop:aspectj-autoproxy />

Aspect


package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class NotVeryUsefulAspect {

}

Pointcut


@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature

Combining pointcut expressions


@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}

@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}

@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}

@Aspect
public class BeforeAspect {

@Pointcut("execution(* com.apress.prospring2.ch06.services.*.*(..))")
private void serviceExecution() { }
@Pointcut(
"execution(* com.apress.prospring2.ch06.services.UserService.login(..))")
private void loginExecution() { }
@Before("serviceExecution() && !loginExecution()")
public void beforeLogin() throws Throwable {
if (SecurityContext.getCurrentUser() == null)
throw new RuntimeException("Must login to call this method.");
}
}

Sharing common pointcut definitions


package com.xyz.someapp;

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.xyz.someapp.web package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.web..*)")
public void inWebLayer() {}

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

/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.someapp.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.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.xyz.someapp.abc.service and com.xyz.def.service) then
* the pointcut expression "execution(* com.xyz.someapp..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.xyz.someapp.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.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {}

}

Examples of common pointcut expressions

execution(public * *(..))
the execution of any public method
execution(* set*(..))
the execution of any method with a name beginning with "set"
execution(* com.xyz.service.AccountService.*(..))
the execution of any method defined by the AccountService interface
execution(* com.xyz.service.*.*(..))
he execution of any method defined in the service package
execution(* com.xyz.service..*.*(..))
the execution of any method defined in the service package or a sub-package
within(com.xyz.service.*)
any join point (method execution only in Spring AOP) within the service package
within(com.xyz.service.*)
any join point (method execution only in Spring AOP) within the service package
within(com.xyz.service..*)
any join point (method execution only in Spring AOP) within the service package or a sub-package
this(com.xyz.service.AccountService)
any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface
target(com.xyz.service.AccountService)
any join point (method execution only in Spring AOP) where the target object implements the AccountService interface
args(java.io.Serializable)
any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable
@target(org.springframework.transaction.annotation.Transactional)
any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation
@annotation(org.springframework.transaction.annotation.Transactional)
any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation
@args(com.xyz.security.Classified)
any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the @Classified annotation
bean(tradeService
any join point (method execution only in Spring AOP) on a Spring bean named 'tradeService'
bean(*Service)
any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service'


Advice

As parameter of advice method you can use org.aspectj.lang.JoinPoint. Class which implements this interface have method: getTarget(), getArgs(), getSignature(), getThis(). You can use this method in advice. For example see @After advice.

Advice with reference to pointcut


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

@Aspect
public class BeforeExample {

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}

}

Advice with in-place pointcut


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

@Aspect
public class BeforeExample {

@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}

}

After returning advice


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

@Aspect
public class AfterReturningExample {

@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}

}

After throwing advice


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

@Aspect
public class AfterThrowingExample {

@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}

}

After (finally) advice


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

@Aspect
public class AfterFinallyExample {

@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock( JoinPoint jp ) {
// ...
Object[] targetMethodArgs = jp.getArgs();
//...
}

}

Around advice


import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class AroundExample {

@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}

}

Passing parameters to advice


@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
public void validateAccount(Account account) {
// ...
}

@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
private void accountDataAccessOperation(Account account) {}

@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}

@Before(
value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
argNames="bean,auditable")
public void audit(JoinPoint jp, Object bean, Auditable auditable) {
AuditCode code = auditable.value();
// ... use code, bean, and jp
}

3 comments:

  1. This is example that i am looking for. Was stuck with Around advices, realized that Before advices was the one that i should use. Thanks

    ReplyDelete
  2. Thank you very much. I try to find how to use the reference pointcus a day. You save a day for me.

    ReplyDelete