切面类
@Component @Aspect public class LoggingAspect { @Before("execution(public int com.dudu.aspect.*.*(int,int))") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println(methodName + "方法执行开始:" + args); } }配置
<aop:aspectj-autoproxy/>@Before 在方法执行之前执行 @After 在方法执行之后执行,不管方法是否正常结束,且此时无法访问目标方法的返回值 @AfterReturning 在方法正常执行后执行,此时可以获取目标方法的返回值 @AfterThrowing 在方法产生异常后执行,可以指定异常类型 @Around 环绕通知,类似于动态代理的全过程,必须有返回值,返回值即为目标方法的返回值
AfterReturning通知
@AfterReturning(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))" , returning = "result") public void afterMethodReturn(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("AfterReturning === " + methodName + "方法执行结束;" + result); }AfterThrowing通知
@AfterThrowing(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))" , throwing = "ex") //此处指定的异常类型也是限定条件,只有在出现对应异常时,通知才会执行 public void afterMethodThrow(JoinPoint joinPoint, Throwable ex) { String methodName = joinPoint.getSignature().getName(); System.out.println("AfterThrowing === " + methodName + "方法执行结束;" + ex); }Around通知
@Around(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))") public Object aroundMethod(ProceedingJoinPoint point) {//必要的参数 String methodName = point.getSignature().getName(); List<Object> args = Arrays.asList(point.getArgs()); Object result = null; try { System.out.println("Before === " + methodName + "方法执行开始:" + args); result = point.proceed();//执行目标方法 System.out.println("AfterReturning === " + methodName + "方法执行结束;" + result); } catch (Throwable throwable) { System.out.println("AfterThrowing === " + methodName + "方法执行结束;" + throwable); throw new RuntimeException(throwable); } System.out.println("After === " + methodName + "方法执行结束;"); return result; }注解内的参数为切入点表达式,指明通知对哪些方法生效
表达式格式:访问修饰符 返回值 包名.类名.方法名(参数列表) 标准写法:public int com.dudu.aspect.CalculatorImpl.add(int, int) 访问修饰符可以省略:int com.dudu.aspect.CalculatorImpl.add(int, int) 返回值可以使用通配符:* com.dudu.aspect.CalculatorImpl.add(int, int) 包名也可以使用通配符,但是包的层数必须对应:* *.*.*.CalculatorImpl.add(int, int) 也可以使用 … 来表示当前包及其子包:* *…CalculatorImpl.add(int, int) 类名和方法名都可以使用通配符:* *…*.* (int, int) 参数列表可以使用通配符,但是参数的个数必须对应,也可以使用 … 来表示有无参数均可 全通配写法为:* *…*.*(…)
JoinPoint类:可以获取一些连接细节
joinPoint.getArgs() 获取参数列表 joinPoint.getSignature().getName() 获取方法名
切面的优先级(@Order注解) 数字越小,优先级越高
@Order(2) @Component @Aspect public class LoggingAspect { } 重用切入点表达式 //声明 @Pointcut(value = "execution(* com.dudu.aspect.CalculatorImpl.*(..))") public void desc(){} //使用,使用全限定类名加方法名可以跨包使用 @AfterReturning("desc()") public void afterMethodReturn(JoinPoint joinPoint, Object result) { //方法体 }