Spring AOP使用

2023-09-15 19:26:15

Spring AOP是什么?

AOP(面向切面编程):将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被命名为“切面”(Aspect),便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性;

在Spring AOP中,切面由切点(Pointcut)和通知(Advice)组成。切点是一个表达式,用于匹配哪些方法需要被横切,通知是在切点位置执行的代码,表示横切逻辑。

切点表达式配置语法:
execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
execution(public void com.apesource.service.ServiceImp.findAll())

  1. 修饰符可以省略代表任意        execution(返回值 包名称.类名称.方法名称(参数列表))
  2. 返回值可以使用“*”代表任意        execution(* 包名称.类名称.方法名称(参数列表))
  3. 包名可以使用“*”代表任意名称        execution(* *.*.*.类名称.方法名称(参数列表))
  4. 包名可以使用“..”代表任意个数         execution(* *...类名称.方法名称(参数列表))
  5. 类名与方法名可以使用“*”代表任意        execution(* *...*.*(参数列表))
  6. 参数列表可以使用".."代表任意个数任意类型        execution(* *...*.*(..))

    如果有参数        int======>int        String===>java.lang.String

Spring AOP提供了几种常见的通知类型,包括:

  • 前置通知(Before):在方法执行前执行的逻辑
  • 后置通知(After):在方法执行后执行的逻辑
  • 返回通知(After-returning):在方法成功返回后执行的逻辑
  • 异常通知(After-throwing):在方法抛出异常后执行的逻辑
  • 环绕通知(Around):在方法执行前后都可以执行的逻辑,可以控制目标方法的执行流程

Spring AOP 基于动态代理实现:

  • 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象;
  • 如果被代理的对象,没有实现某个接口, Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理;

Spring AOP可以通过注解或XML配置的方式来定义切点和通知,并且可以与Spring的IOC容器无缝集成,使得切面和目标对象的创建和管理变得更加简单。 

1⃣️XML

1.添加依赖:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.28</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

2.创建切面类:

public class LoggerUtil {
    //前置通知
    public void beforeMethod(){
        System.out.println("前置通知=====>"+new Date());
    }
    //返回通知
    public void afterRrturnMethod(){
        System.out.println("返回通知=====>"+new Date());
    }
    //异常通知
    public void throwMethod(){
        System.out.println("异常通知=====>"+new Date());
    }
    //后置通知
    public void afterMethod(){
        System.out.println("后置通知=====>"+new Date());
    }

    //环绕通知
    public Object arroundMethod(ProceedingJoinPoint pjp){
        Object obj = null;
        try {
            //环绕通知---前置通知
            System.out.println("环绕通知---前置通知");
            Object[] objs = pjp.getArgs();
            obj = pjp.proceed(objs);
            //环绕通知---返回通知
            System.out.println("环绕通知---返回通知");
        } catch (Throwable throwable) {
            //环绕通知---异常通知
            System.out.println("环绕通知---异常通知");
            throwable.printStackTrace();
        } finally {
            //环绕通知---后置通知
            System.out.println("环绕通知---后置通知");
        }
        return obj;
    }
}

3.配置XML:

    <!--开启aop配置-->
    <aop:config>
        <!--切面-->
        <aop:aspect id="mian" ref="loggerUtil">
            <!--切点-->            
            <aop:pointcut id="dian" expression="execution(* *...*.*(..))"/>
            <!--通知-->
            <aop:before method="beforeMethod" pointcut-ref="dian"></aop:before>
            <aop:after-returning method="afterRrturnMethod" pointcut-ref="dian"></aop:after-returning>
            <aop:after-throwing method="throwMethod" pointcut-ref="dian"></aop:after-throwing>
            <aop:after method="afterMethod" pointcut-ref="dian"></aop:after>
            <aop:around method="arroundMethod" pointcut-ref="dian"></aop:around>
        </aop:aspect>
    </aop:config>

2⃣️注解

1.添加依赖:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.28</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

2.创建切面类:

@Component
@Aspect//切面
//@EnableAspectJAutoProxy 
public class LoggerUtil {
    //切点
    @Pointcut(value="execution(* com.apesource.service.*.*(..))")
    public void dian(){}
    
    //前置通知
//    @Before("dian()")
    public void beforeMethod(){
        System.out.println("前置通知=====>"+new Date());
    }
    //返回通知
//    @AfterReturning("dian()")
    public void afterRrturnMethod(){
        System.out.println("返回通知=====>"+new Date());
    }
    //异常通知
//    @AfterThrowing("dian()")
    public void throwMethod(){
        System.out.println("异常通知=====>"+new Date());
    }
    //后置通知
//    @After("dian()")
    public void afterMethod(){
        System.out.println("后置通知=====>"+new Date());
    }

    //环绕通知
    @Around("dian()")
    public Object arroundMethod(ProceedingJoinPoint point){
        Object returnObj = null;//执行切点方法
        try {
            System.out.println("环绕通知====>前置通知");
            //切点
            Object[] obj = point.getArgs();//切点方法的参数
            returnObj = point.proceed(obj);
            System.out.println("环绕通知====>返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知====>异常通知");
        } finally {
            System.out.println("环绕通知====>后置通知");
        }
        return returnObj;//切点方法的返回值
    }
}

3.配置XML:(也大可不配直接注解)

  <!--aop的自动代理 @EnableAspectJAutoProxy可以替换标签-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

更多推荐

数据工程中的单元测试完全指南

在数据工程领域中,经常被忽视的一项实践是单元测试。许多人可能认为单元测试仅仅是一种软件开发方法论,但事实远非如此。随着我们努力构建稳健、无错误的数据流水线和SQL数据模型,单元测试在数据工程中的价值变得越来越清晰。本文带你深入探索如何将这些成熟的软件工程实践应用到数据工程中。1单元测试的重要性在数据工程的背景下,采用单

【Android取证篇】华为设备跳出“允许USB调试“界面方法的不同方法

【Android取证篇】华为设备跳出"允许USB调试"界面方法的不同方法华为设备在鸿蒙OS3系统之后,部分设备启用"允许USB调试"方式会有所变化,再次做个记录—【蘇小沐】1.实验环境系统版本Windows11专业工作站版22H2(22621.2134);HarmonyOS3;(一)【Android取证篇】华为设备无法

dockerfile文件详解(常用命令)

在编写Dockerfile时,考虑以下最佳实践:最小化镜像大小:尽量使用轻量级的基础镜像,并在构建过程中尽量减少不必要的层。合理使用缓存:Docker会尝试重用缓存的层,如果一个步骤发生变化,后续步骤将失去缓存。因此,将频繁变化的步骤放在最后,以便充分利用缓存。清理不必要的文件:在构建镜像时,删除不必要的文件和缓存以减

【从0学习Solidity】13. 继承

【从0学习Solidity】13.继承博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!本文收录于不写代码没饭吃的学习汇报系列,大家有兴趣的可

Java实现图书管理系统

一、分析有主要对象二、整理思路三、框架的搭建四、操作内部的具体实现一、分析主要对象我们做的图书管理系统的目的,是可以根据不同的用户,所能执行的操作不一样,主要有增删查改图书等操作,选择这些不同的操作会给我们反馈不一样的结果,而我们的主要对象就有书、书架、用户、操作这四个对象。二、整理思路书里面可以放书名、作者、价格等变

VS2019的SDL2项目配置

库下载SimpleDirectMediaLayer-Homepage对于Windows下使用VS2019开发的选手,应该直接选VC后缀了。VS目录配置首先VS2019创建一个空项目,新加入一个源文件,代码如下:/*ThissourcecodecopyrightedbyLazyFoo'Productions2004-20

【C++】topk问题

解决topK问题是寻找给定数据集中前K个最大或最小的元素。常见有三种算法:堆排序维护一个大小为K的最小(或最大)堆。遍历数据集,将元素插入堆中,如果堆大小超过K,则删除堆顶元素。遍历结束后,堆中剩余的K个元素就是前K个最小(或最大)的元素。时间复杂度:O(NlogK),其中N为数据集大小。示例代码如下:#include

Docker 恶意挖矿镜像应急实例

01、概述当网络流量监控发现某台运行多个docker容器的主机主动连接到一个疑似挖矿矿池的地址时,需要快速响应和排查,以阻止进一步的损害。面对docker容器的场景下,如何快速分析和识别恶意挖矿容器?本文将分享一种应急响应思路,用于排查运行多个Docker容器的主机中可能存在的恶意挖矿容器。02、定位容器在宿主机上通过

C 风格文件输入/输出---错误处理---(std::clearerr,std::feof,std::ferror,std::perror)

C++标准库的CI/O子集实现C风格流输入/输出操作。<cstdio>头文件提供通用文件支持并提供有窄和多字节字符输入/输出能力的函数,而<cwchar>头文件提供有宽字符输入/输出能力的函数。错误处理清除错误std::clearerrvoidclearerr(std::FILE*stream);重置给定文件流的错误标

APP产品经理的主要内容(合集)

APP产品经理的主要内容1职责:1.成产品的功能、流程、界面设计,协调设计资源落实产品交互、原型设计;2.负责产品上线后客户反馈跟踪,并根据产品规划策略和客户反馈优先级落实产品改进设计计划,不断提升竞争力。3.关注竞争对手和用户的产品反馈,分析并提供应对方案,改进相关产品;4.保证产品的可用性和易用性,为产品体验和效果

Time-distributed 的理解

“Time-distributed”是一种用于深度学习处理序列数据的技术,它将神经网络中的层或网络独立地应用于序列的每个时间步长。在典型的前馈神经网络中,输入数据会被馈送到网络中,并且相同的权重会被应用于所有的输入特征。但是,当处理序列数据,如时间序列或自然语言时,我们需要在每个时间步长上应用相同的权重来捕捉时间信息。

热文推荐