一. 知识储备
- 在同一个连接点上应用不止一个切面时,除非明确指定,否则他们的优先级是不确定的
- 切面的优先级可以实现Ordered接口或利用@Order注释指定
- 实现Ordered接口,getOrder()方法的返回值越小,优先级越高
- 若使用@Order注解,序号出现在括号中,设置的值越小,优先级越高
二. 例子
ValidationAspect.java
package com.atguigu.spring.aop.aspectJ;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 验证切面
* @author user
*
*/
@Component
@Aspect
@Order(2) //默认值int的最大值2147483647
public class ValidationAspect {
@Before(value="execution(* com.atguigu.spring.aop.aspectJ.*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("ValidationAspect==> The method " + methodName + " begin with : " + Arrays.asList(args));
}
}
LoggingAspect.java
package com.atguigu.spring.aop.aspectJ;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 切面:日志切面
* @author user
*
*/
@Component //标识为一个组件
@Aspect //标识为一个切面
@Order(3)
public class LoggingAspect {
/**
* 前置通知:在方法执行之前执行
* value: 切入点表达式
* 连接点对象: JoinPoint , 包含当前连接点相关信息(即当前作用的方法,即切入点表达式里面的方法)
*
*/
@Before(value = "execution(public int com.atguigu.spring.aop.aspectJ.ArithmeticCalculatorImpl.add(int, int))")
public void beforeMethod(JoinPoint joinPoint) {
//方法名
String methodName = joinPoint.getSignature().getName();
//方法的参数列表
Object[] args = joinPoint.getArgs();
System.out.println("LoggingAspect==> The method " + methodName + " begin with : " + Arrays.asList(args));
}
/**
* 后置通知:在方法执行之后,不管目标方法有无抛出异常都会执行
* 切入点表达式:
* * : 任意修饰符任意返回值
* * : 包下的任意类
* * :类中任意方法
* ..: 任意参数列表
*/
@After(value="execution(* com.atguigu.spring.aop.aspectJ.*.*(..))")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("LoggingAspect==> The method " + methodName + " ends.");
}
/**
* 异常通知:在目标方法抛出异常后执行
* 通过throwing="变量名"来接收异常信息,throwing指定的名字必须要与方法中用于接收异常的形参名一致
*
* 还可以通过方法中接收异常的形参类型 来 指定抛出什么异常才执行异常通知
*/
@AfterThrowing(value="execution(* com.atguigu.spring.aop.aspectJ.*.*(..))", throwing="ex")
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
System.out.println("LoggingAspect==> The method " + methodName + " occurs Exception: " + ex);
}
/**
* 返回通知:在目标方法正常返回后执行,可以获取到方法的返回值
* 通过returning="变量名"来接收方法的返回值,
* returning指定的名字必须要与方法中用于接收返回值的形参名一致
*/
@AfterReturning(value="execution(* com.atguigu.spring.aop.aspectJ.*.*(..))", returning="result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("LoggingAspect==> The method " + methodName + "ends with: " + result);
}
/**
* 环绕通知:环绕着目标方法执行,可以理解为前置 后置 返回 异常的结合,类似于动态代理的整个过程
*
*/
@Around(value="execution(* com.atguigu.spring.aop.aspectJ.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint pjp) {
try {
//前置
//调用目标方法
Object result = pjp.proceed();
//返回
return result;
} catch (Throwable e) {
// TODO Auto-generated catch block
//异常
e.printStackTrace();
}finally {
//后置
}
return null;
}
}