放一些简单易用的spring aspect 语法手册。
完整代码:spring-aop
@Aspect
和@Configuration
来标记Aspect。参考LogingAspect就像之前写的btrace手册一样, 为了方便查找和实际操作,想分享一些关于写Aspect相关的cheatsheet。
@Transactional
就是在企业应用中事务相关的的横切面。或者某个用来记录日志的切面。一般情况下切面会包含一个完整within(com.example.controller.*)
)。本文也将提供更多的例子方便查找。IsModified
来方便实现缓存。advised object
)。因为spring用代理来实现的,所以这个也叫被代理对象。proceed
方法来示例 | 解释 |
---|---|
within(com.xyz.service.*) | 执行com.xyz.service(不包括子包)的所有类的方法 |
within(com.xyz.service..*) | 执行com.xyz.service(包括子包)的所有类的方法 |
this(com.xyz.service.AccountService) | 执行实现了AccountService的接口的类 |
execution(* com.example.springaop.controller.*.*(..)) | 执行 |
execution(public * *(..)) | 执行所有public方法 |
execution(* set*(..)) | 执行所有方法名以set开始的方法 |
execution(* com.xyz.service.AccountService.*(..)) | 执行所有在com.xyz.service.AccountService类里面的方法。 |
execution(* com.xyz.service.*.*(..)) | 执行所有在com.xyz.service里面的方法(不包括子包) |
execution(* com.xyz.service..*.*(..)) | 执行所有在com.xyz.service里面的方法(包括子包) |
@within(org.springframework.transaction.annotation.Transactional) | 某个类具有@Transactional注解 |
@annotation(org.springframework.transaction.annotation.Transactional) | 某个方法具有@Transactional注解 |
具体语法:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
JoinPoint
获取当前执行方法的状态。后续几个都可以获取该参数。 @Before("execution(* com.xyz.myapp.dao.*.*(..))")public void doAccessCheck(JoinPoint jp) {}
AfterReturning
正常返回后:
@AfterReturning(pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",returning="retVal")public void doAccessCheck(Object retVal) {// ...}
AfterThrowing
抛异常后:
@AfterThrowing(pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",throwing="ex")
public void doRecoveryActions(DataAccessException ex) {// ...
}
Arround
环绕通知可以使用ProceedingJoinPoint.proceed
来调用原始的实现。
@Around("com.xyz.myapp.CommonPointcuts.businessService()")public Object timing(ProceedingJoinPoint jp) throws Throwable {// start stopwatchObject retVal = jp.proceed(); // stop stopwatchreturn retVal;}
@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {// ...
}
上面例子中account是第一个参数。 当然dataAccessOperation指定的PointCut必须保证有至少一个参数。
@Around, @Before, @After, @AfterReturning, @AfterThrowing
不同Aspect的还可以通过@Order指定顺序
用来统计运行时长和记录请求的例子:
package com.example.springaop;import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.*;import java.util.*;@Configuration
@Aspect
public class LogingAspect {@Pointcut("within(com.example.springaop.controller.*)")public void ctrlMethod() {}@Pointcut("execution(public * *(..)) ")public void publicMethod() {}@Around("ctrlMethod() && publicMethod()")public Object loggingAndTiming(ProceedingJoinPoint jp) throws Throwable {long t1 = System.currentTimeMillis();String className = jp.getSignature().getDeclaringTypeName();String methodName = jp.getSignature().getName();String args = Arrays.toString(jp.getArgs());try {return jp.proceed();} catch (Throwable e) {throw e;}finally {System.out.println(String.format("%s.%s with args: %s , cost time: %d",className, methodName, args, System.currentTimeMillis() - t1));}}
}