五、AOP
业务逻辑类:实现业务逻辑的类,包含目标方法
切面类:包含通知方法和切入点的类
切入点表达式:告诉通知方法作用在哪个目标方法的表达式
通知方法:按照通知类型,在目标方法的运行到指定位置时被额外执行的方法
通知方法注解
| 类型 | 注解 | 被调用时机 |
|---|---|---|
| 前置通知 | @Before | 在目标方法运行之前运行 |
| 后置通知 | @After | 在目标方法运行之后,返回之前运行 |
| 返回通知 | @AfterReturning | 在目标方法正常返回之后运行 |
| 异常通知 | @AfterThrowing | 在目标方法出现异常之后运行 |
| 环绕通知 | @Around | 动态代理,手动调用目标方法 |
获取额外信息
在通知方法中可以获取一些有用的信息,如切入点(目标方法信息),返回值,异常信息等
我们只需要在通知方法上加上对应的参数
以下是一些常用的场景
注:JoinPoint参数一定要出现在通知方法参数列表的第一位!
@Before("public User com.peck.service.UserService.*(..)")
public void beforeMethod(JoinPoint joinPoint){
//获取参数列表
Object[] args = joinPoint.getArgs();
//获取方法签名
MethodSignature ms = (MethodSignature)joinPoint.getSignature();
//获取参数类型
Class[] paramTypeArray = ms.getParameterTypes();
}
//JoinPoint参数一定要出现在通知方法参数列表的第一位
@AfterReturning(value="pointcut()",returning="result")
public void afterReturnMethod(JoinPoint joinPoint,Object result){
//返回值将会被传入result参数
System.out.println(result);
}
@AfterThrowing(value="pointcut()",throwing="exception")
public void afterThrowMethod(JoinPoint joinPoint,Exception exception){
//异常将会被传入exception参数
System.out.println(exception);
}
围绕通知
围绕通知方法比较特殊,可以具体看下面例子的注释
@Aroud("pointcut()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throw Throwable{
Object[]args = joinPoint.getArgs(); //获得参数列表
//其他操作...,修改参数
//一定要使用带参的proceed方法,不然还是使用目标方法自己的参数
Object result = joinPoint.proceed(args);
//这里要返回目标方法的结果,不然会返回null
return result;
}
切入点表达式
切入点表达式可以写在通知方法注解的value属性中,也可以写在@Pointcut注解中。当我们需要重复用到同一个切入点表达式时可以使用后者。
以下是几种常用的切入店表达式写法,详见官方文档
注解属性方式
//1. 在getUserById方法之前运行
@Before("public User com.peck.service.UserService.getUserById(int)")
public void beforeMethod(){}
//2. 在UserService类中的所有方法之前运行 *代表所有方法 ..代表任意参数
@Before("public User com.peck.service.UserService.*(..)")
public void beforeMethod(){}
@Pointcut方式
//随便写个public空方法,作为切入点
@Pointcut("execution(public User com.peck.service.UserService.*(..))")
public void pointCut(){}
//若和@Pointcut在同一个类下,可直接引用改切入点
@Before("pointCut()")
public void beforeMethod(){}
//若和@Pointcut在不在一个类下,引用该切入点需要加上包名
@Before("copm.peck.aop.pointcut.pointCut()")
public void beforeMethod(){}
使用步骤
- 创建一个业务逻辑类和切面类,并在切面类上标注
@Aspect注解 - 在切面类中编写通知方法和切入点表达式
- 把业务逻辑类和切面类均加入容器
- 在配置类中添加
@EnableAspectJAutoProxy开启基于注解的aop - 从容器中取出业务逻辑类使用