Spring 复习 五、AOP

177 阅读3分钟

五、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(){}

使用步骤

  1. 创建一个业务逻辑类和切面类,并在切面类上标注@Aspect注解
  2. 在切面类中编写通知方法和切入点表达式
  3. 把业务逻辑类和切面类均加入容器
  4. 在配置类中添加@EnableAspectJAutoProxy开启基于注解的aop
  5. 容器中取出业务逻辑类使用