Spring 全家桶之 Spring Framework 5.3(五)- AOP(三)

简介: Spring 全家桶之 Spring Framework 5.3(五)- AOP

4.获取目标方法的详细信息

需要参数JoinPoint类,封装了目标方法的详细信息

获取方法参数,joinPoint.getSignature())可以获取方法名,joinPoint.getArgs()可以获取参数列表

@Before("addPointCut()")
public void logStart(JoinPoint joinPoint ){
    System.out.println(this.getClass().getName() + "切面类运行-目标方法调用前的输出-@Before前置通知");
    System.out.println("目标方法名:" + joinPoint.getSignature());
    System.out.println("目标方法参数:" + Arrays.toString(joinPoint.getArgs()));
}
复制代码

执行测试方法中的add()

获取返回值,需要定义一个变量来接收,方法在入参中,为了能接收各种类型的参数因此最好定义为Object类型

@AfterReturning(value = "addPointCut()", returning = "result")
public void logReturn(Object result){
    System.out.println(this.getClass().getName() + "切面类运行-目标方法返回:" + result + ",@AfterReturning正常返回");
}
复制代码

异常同样

@AfterThrowing(value = "divPointCut()", throwing = "e")
public void logException(Exception e){
    System.out.println(this.getClass().getName() + "切面类运行-目标方法抛出异常:" + e);
}
复制代码

异常也可以指定传入哪种异常,方法执行爆出的异常符合传入的异常才会打印出异常信息,否则不会,所以传入的异常类型要尽量是Exception,如果可以确切的知道方法爆出的异常,可以指定具体异常来接收, Result同样也可以指定具体类型来接收返回值

执行add方法和div方法的测试

image.png

5.切入点表达式

@Pointcut("execution(public * com.citi.util.impl.AppleCalculator.add(int, int))")
public void addPointCut(){
}
@Pointcut("execution(public * com.citi.util.impl.AppleCalculator.div(int, int))")
public void divPointCut(){
}
复制代码

@Pointcut注解定一个切点表达式,方法内部不用实现任何功能

6.环绕通知

其实就是一个动态代理

@Around("addPointCut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    String methodName = joinPoint.getSignature().getName();
    System.out.println("环绕通知-方法执行前");
    Object o = null;
    try {
        System.out.println("环绕通知-前置通知," + methodName + "方法开始执行");
        // 反射执行目标方法
        o = joinPoint.proceed();
        System.out.println("环绕通知-返回通知," + methodName + "返回值:" + o.toString());
    } catch (Exception e){
        System.out.println("环绕通知-异常通知," + methodName + "异常信息为:" + e);
    } finally {
        System.out.println("环绕通知-后置通知," + methodName + "方法执行结束");
    }
    return o;
}
复制代码

将普通通知的注解注释,执行add方法

image.png

将切入点表达式改为divPointcut,执行div方法的测试

image.png

普通通知和环绕通知同时存在时的执行顺序,将环绕通知的切点表达式改为addPointcut,将普通通知方法的注解注释取消,执行add方法的测试

image.png

7.有多个切面类的情况下的运行顺序

新增切面类

@Component
@Aspect
public class VerifyAspect {
    @Pointcut("execution(public * com.citi.util.impl.AppleCalculator.add(int, int))")
    public void addPointCut(){
    }
    @Pointcut("execution(public * com.citi.util.impl.AppleCalculator.div(int, int))")
    public void divPointCut(){
    }
    @Before("addPointCut()")
    public void verifyStart(JoinPoint joinPoint ){
        System.out.println(this.getClass().getName() + "切面类执行-目标方法调用前的输出-@Before");
        //System.out.println("目标方法名:" + joinPoint.getSignature());
        //System.out.println("目标方法参数:" + Arrays.toString(joinPoint.getArgs()));
    }
    @AfterReturning(value = "addPointCut()",returning = "result")
    public void verifyReturn(Object result){
        System.out.println(this.getClass().getName() + "切面类执行-方法执行后输出返回值:" + result + ",@AfterReturning正常返回");
    }
    @After(value = "addPointCut()")
    public void verifyEnd(JoinPoint joinPoint){
        System.out.println(this.getClass().getName() + "切面类执行-目标方法调用结束,@After后置通知");
    }
    @AfterThrowing(value = "divPointCut()",throwing = "e")
    public void verifyException(Exception e){
        System.out.println(this.getClass().getName() + "切面类执行-方法抛出异常:" + e);
    }
}
复制代码

LogAspect暂时注销环绕通知

@Component
@Aspect
public class LogAspect {
    @Pointcut("execution(public * com.citi.util.impl.AppleCalculator.add(int, int))")
    public void addPointCut(){
    }
    @Pointcut("execution(public * com.citi.util.impl.AppleCalculator.div(int, int))")
    public void divPointCut(){
    }
    @Before("addPointCut()")
    public void logStart(JoinPoint joinPoint ){
        System.out.println(this.getClass().getName() + "切面类运行-目标方法调用前的输出-@Before前置通知");
        //System.out.println("目标方法名:" + joinPoint.getSignature());
        //System.out.println("目标方法参数:" + Arrays.toString(joinPoint.getArgs()));
    }
    @AfterReturning(value = "addPointCut()", returning = "result")
    public void logReturn(Object result){
        System.out.println(this.getClass().getName() + "切面类运行-目标方法返回:" + result + ",@AfterReturning正常返回");
    }
    @After("addPointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(this.getClass().getName() + "方法调用结束,@After后置通知");
    }
    @AfterThrowing(value = "addPointCut()", throwing = "e")
    public void logException(Exception e){
        System.out.println(this.getClass().getName() + "切面类运行-目标方法抛出异常:" + e);
    }
    //@Around("addPointCut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("环绕通知-方法执行前");
        Object o = null;
        try {
            System.out.println("环绕通知-前置通知," + methodName + "方法开始执行");
            // 反射执行目标方法
            o = joinPoint.proceed();
            System.out.println("环绕通知-返回通知," + methodName + "返回值:" + o.toString());
        } catch (Exception e){
            System.out.println("环绕通知-异常通知," + methodName + "异常信息为:" + e);
        } finally {
            System.out.println("环绕通知-后置通知," + methodName + "方法执行结束");
        }
        return o;
    }
}
复制代码

运行add方法的测试方法

image.png

执行顺序,先进后出

image.png

切面类先后执行是根据切面类名字首字母排序,讲VerifyAspect改为AerifyAspect,再次执行add的测试方法

image.png

要想改变按照切面类字母顺序执行切面类,可以在类上增加@Order注解,数值越小优先级越高,给LogAspect加上@Order(1),默认是2147483647,再次执行add方法的测试方法

image.png

有环绕通知的情况下,将LogAspect的环绕通知注解注释取消,并在输出中加上类名标识

image.png

环绕通知加在哪个切面,那个切面执行环绕,环绕通知优先执行,环绕通知中执行方法

AOP使用场景:

  • AOP加日志保存到数据库
  • AOP作权限验证
  • AOP作安全检查
  • AOP作事务控制


相关文章
|
3天前
|
XML 监控 安全
Spring特性之一——AOP面向切面编程
Spring特性之一——AOP面向切面编程
15 1
|
3天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
1天前
|
前端开发 Java 关系型数据库
使用IDEA搭建一个Spring + AOP (权限管理 ) + Spring MVC
使用IDEA搭建一个Spring + AOP (权限管理 ) + Spring MVC
|
3天前
|
JSON 前端开发 Java
【JavaEE】Spring全家桶实现AOP-统一处理
【JavaEE】Spring全家桶实现AOP-统一处理
5 0
|
3天前
|
前端开发 Java 开发者
【JavaEE】面向切面编程AOP是什么-Spring AOP框架的基本使用
【JavaEE】面向切面编程AOP是什么-Spring AOP框架的基本使用
10 0
|
3天前
|
Java Spring 容器
Spring AOP浅谈
Spring AOP浅谈
10 1
|
3天前
|
XML Java 数据格式
Spring高手之路18——从XML配置角度理解Spring AOP
本文是全面解析面向切面编程的实践指南。通过深入讲解切面、连接点、通知等关键概念,以及通过XML配置实现Spring AOP的步骤。
22 6
Spring高手之路18——从XML配置角度理解Spring AOP
|
3天前
|
XML Java 数据格式
Spring使用AOP 的其他方式
Spring使用AOP 的其他方式
16 2
|
3天前
|
XML Java 数据格式
Spring 项目如何使用AOP
Spring 项目如何使用AOP
25 2
|
3天前
|
Java 开发者 Spring
Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
【5月更文挑战第1天】Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
25 5