[Spring Framework]AOP配置管理③(AOP通知获取数据)

简介: AOP配置管理③(AOP通知获取数据)

@[TOC]

AOP通知获取数据

目前我们写AOP仅仅是在原始方法前后追加一些操作,接下来我们要说说AOP中数据相关的内容,我们将从以下三个方面来研究切入点的相关信息:

  • 获取参数
  • 获取返回值
  • 获取异常

前面我们介绍通知类型的时候总共讲了五种,那么对于这五种类型都会有参数,返回值和异常吗?

我们先来一个个分析下:

  • 获取切入点方法的参数,所有的通知类型都可以获取参数

    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知
    • ProceedingJoinPoint:适用于环绕通知
  • 获取切入点方法返回值,前置和抛出异常后通知是没有返回值,后置通知可有可无,所以不做研究,我们主要讨论:

    • 返回后通知
    • 环绕通知
  • 获取切入点方法运行异常信息,前置和返回后通知是不会有,后置通知可有可无,所以不做研究,我们只讨论:

    • 抛出异常后通知
    • 环绕通知

项目环境

首先我们准备,一个接口以及其实现类:

public interface BookDao {
    public String findName(int id);
}

@Repository
public class BookDaoImpl implements BookDao {

    public String findName(int id) {
        System.out.println("id:"+id);
        return "CSDN";
    }
}

通知类:

@Component
@Aspect
public class MyAdvice2 {
    @Pointcut("execution(* *BookDao4.findName(..))")
    private void pt(){}

    @Before("pt()")
    public void before() {
        System.out.println("before advice ..." );
    }

    @After("pt()")
    public void after() {
        System.out.println("after advice ...");
    }

    @Around("pt()")
    public Object around() throws Throwable{
        Object ret = pjp.proceed();
        return ret;
    }
    @AfterReturning("pt()")
    public void afterReturning() {
        System.out.println("afterReturning advice ...");
    }


    @AfterThrowing("pt()")
    public void afterThrowing() {
        System.out.println("afterThrowing advice ...");
    }
}

然后我们的测试demo:

public class App12 {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao4 bookDao = ctx.getBean(BookDao4.class);
        String name = bookDao.findName(100);
        System.out.println(name);
    }

}

获取切入点方法的参数

因为所有的通知类型都可以获取切入点方法的参数,所以这里我们分为两种来讨论:

  • 非环绕通知获取方式
  • 环绕通知获取方式

非环绕通知获取方式

核心操作:
==在方法上添加JoinPoint,通过JoinPoint来获取参数==
@Component
@Aspect
public class MyAdvice2 {
    @Pointcut("execution(* *.BookDao4.findName(..))")
    private void pt(){}

    @Before("pt()")
    public void before(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ..." );
    }
        //...其他的略
}

结果:
在这里插入图片描述
这里使用一个Object数组是因为参数个数不确定,参数类型也不确定,我们再在原切入点方法中添加一个参数看看效果:
在这里插入图片描述
在这里插入图片描述

运行结果:
在这里插入图片描述

说明:
使用JoinPoint的方式获取参数适用于 前置后置返回后抛出异常后通知。

环绕通知获取方式

环绕通知使用的是ProceedingJoinPoint,因为ProceedingJoinPoint是JoinPoint类的子类,所以对于ProceedingJoinPoint类中应该也会有对应的getArgs()方法,我们去验证下:

@Component
@Aspect
public class MyAdvice {
    @Pointcut("execution(* *.BookDao4.findName(..))")
    private void pt(){}

    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        Object[] args = proceedingJoinPoint.getArgs();
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("around advice ...");
        System.out.println(Arrays.toString(args));
        return proceed;
    }
    //其他的略
}

执行结果:
在这里插入图片描述
注意:

  • proceedingJoinPoint.proceed()方法是有两个构造方法,分别是:

  • 调用无参数的proceed,当原始方法有参数,会在调用的过程中自动传入参数
  • 所以调用这两个方法的任意一个都可以完成功能
  • 但是当需要修改原始方法的参数时,就只能采用带有参数的方法,如下:

    @Component
    @Aspect
    public class MyAdvice {
        @Pointcut("execution(* *.BookDao4.findName(..))")
        private void pt(){}
    
        @Around("pt()")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
            Object[] args = proceedingJoinPoint.getArgs();
            args[0] = 666;
            Object proceed = proceedingJoinPoint.proceed(args);
                System.out.println("around advice ...");
            System.out.println(Arrays.toString(args));
            return proceed;
    
            }
        //其他的略
    }

    结果:
    在这里插入图片描述

有了这个特性后,我们就可以在环绕通知中对原始方法的参数进行拦截过滤,避免由于参数的问题导致程序无法正确运行,保证代码的健壮性。

获取返回值

对于返回值,只有返回后AfterReturing和环绕Around这两个通知类型可以获取,具体如何获取?

环绕通知获取返回值

    @Component
    @Aspect
    public class MyAdvice {
        @Pointcut("execution(* *.BookDao4.findName(..))")
        private void pt(){}
    
        @Around("pt()")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
            Object[] args = proceedingJoinPoint.getArgs();
            args[0] = 666;
            Object proceed = proceedingJoinPoint.proceed(args);
                System.out.println("around advice ...");
            System.out.println(Arrays.toString(args));
            return proceed;

            }
        //其他的略
    }

上述代码中,proceed就是方法的返回值,我们是可以直接获取,不但可以获取,如果需要还可以进行修改。

返回后通知获取返回值

@Component
@Aspect
public class MyAdvice {
    @Pointcut("execution(* *.BookDao4.findName(..))")
    private void pt(){}

    @AfterReturning(value = "pt()",returning = "str")
    public void afterReturning(Object str) {
        System.out.println(str);
        System.out.println("afterReturning advice ...");
    }
    //其他的略
}

结果;
在这里插入图片描述
==注意:==

(1)参数名的问题

在这里插入图片描述

(2)afterReturning方法参数类型的问题

参数类型可以写成String,但是为了能匹配更多的参数类型,建议写成Object类型

(3)afterReturning方法参数的顺序问题

在这里插入图片描述

获取异常

对于获取抛出的异常,只有抛出异常后AfterThrowing和环绕Around这两个通知类型可以获取,具体如何获取?

环绕通知获取异常

这块比较简单,以前我们是抛出异常,现在只需要将异常捕获,就可以获取到原始方法的异常信息了

@Component
@Aspect
public class MyAdvice {
    @Pointcut("execution(* *.BookDao4.findName(..))")
    private void pt(){}

    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        Object[] args = proceedingJoinPoint.getArgs();
        args[0] = 666;
        Object proceed = null;
        try {
            proceed = proceedingJoinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around advice ...");
        System.out.println(Arrays.toString(args));
        return proceed;

    }
    //其他的略
}

在catch方法中就可以获取到异常,至于获取到异常以后该如何处理,这个就和你的业务需求有关了。

抛出异常后通知获取异常

@Component
@Aspect
public class MyAdvice {
    @Pointcut("execution(* *.BookDao4.findName(..))")
    private void pt(){}

    @AfterThrowing(value = "pt()",throwing = "t")
    public void afterThrowing(Throwable t) {
        System.out.println(t);
        System.out.println("afterThrowing advice ...");
    }
    //其他的略
}

如何让原始方法抛出异常,方式有很多:

在这里插入图片描述

最后的结果:
在这里插入图片描述

==注意:==
在这里插入图片描述
相关文章
|
6天前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
|
14天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
60 8
|
2月前
|
存储 人工智能 Java
Spring AI Alibaba 配置管理,用 Nacos 就够了
本文通过一些实操案例展示了 Spring AI Alibaba + Nacos 在解决 AI 应用中一系列复杂配置管理挑战的方案,从动态 Prompt 模板的灵活调整、模型参数的即时优化,到敏感信息的安全加密存储。Spring AI Alibaba 简化了对接阿里云通义大模型的流程,内置 Nacos 集成也为开发者提供了无缝衔接云端配置托管的捷径,整体上极大提升了 AI 应用开发的灵活性和响应速度。
349 14
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
96 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
91 8
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
53 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
59 4
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
51 1