iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Springboot项目如何快速实现Aop功能
  • 460
分享到

Springboot项目如何快速实现Aop功能

2023-07-05 17:07:22 460人浏览 安东尼
摘要

这篇文章主要讲解了“SpringBoot项目如何快速实现aop功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot项目如何快速实现Aop功能”吧!依赖引入Springboo

这篇文章主要讲解了“SpringBoot项目如何快速实现aop功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot项目如何快速实现Aop功能”吧!

依赖引入

Springboot引入AOP依赖包后,一般来说是不需要再做其他配置了,在比较低的版本或者有其他配置影响了AOP的相关功能,导致aop功能不生效,可以试试在启动类上增加@EnableAspectJAutoProxy来启用;

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-aop</artifactId></dependency>

代码实现

自定义注解@TestAop

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface TestAop {}

ExampleAop .java

@Component@Aspect@Slf4jpublic class ExampleAop {     //切入点:增强标有@TestAop注解的方法    @Pointcut(value = "@annotation(TestAop)")    //切入点签名    public void pointcut() {        System.out.println("pointCut签名。。。");    }     //前置通知    @Before("pointcut()")    public void deBefore(JoinPoint joinPoint) throws Throwable {        log.info("前置通知被执行");        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;    }     //返回通知    @AfterReturning(returning = "ret", pointcut = "pointcut()")    public void doAfterReturning(Object ret) throws Throwable {        log.info("返回通知被执行");        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;    }     //异常通知    @AfterThrowing(throwing = "ex", pointcut = "pointcut()")    public void throwss(JoinPoint jp, Exception ex) {        log.info("异常通知被执行");        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;        //可以从ex中获取到具体的异常信息    }     //后置通知    @After("pointcut()")    public void after(JoinPoint jp) {        log.info("后置通知被执行");        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;    }     @Around("pointcut()")    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        log.info("------环绕通知 start");        String methodName = proceedingJoinPoint.getSignature().getName();        String className = proceedingJoinPoint.getTarget().getClass().getName();        Object[] args = proceedingJoinPoint.getArgs();        String argsName = null;        StringBuilder sb = new StringBuilder();        if (args != null && args.length > 0) {            for (int i = 0; i < args.length; i++) {                if (args[i] != null) {                    sb.append(";").append(args[i].getClass().getName());                }            }            if (sb.toString().length() > 0) {                argsName = sb.toString().substring(1);            }        }        log.info("命中类:{},方法{},参数{};", className, methodName, argsName);        Object proceed = proceedingJoinPoint.proceed();        log.info("------环绕通知 end");        return proceed;    } }

核心注解和类

Aspect,表示当前类是一个切面类,简单理解就是切入点和通知的抽象封装,表述的是切入点和通知方法之间的对应关系;

@Before,前置通知,用于方法上,被@Before注解标记的方法会在被切入方法执行之前执行;

@After,后置通知,用于方法上,被@After注解标记的方法会在被切入方法执行之后执行;

@AfterReturning,返回通知,用于方法上,被@AfterReturning注解标记的方法会在被切入方法返回结果之后执行;

@AfterThrowing:异常通知,用于方法上,被@AfterThrowing注解标记的方法会在被切入方法抛出异常之后执行,一般用于有目的的获取异常信息;

@Aroud:环绕通知,用于方法上,被@Around注解标记的方法会在被切入方法执行前后执行;

@Pointcut,切入点,标记在方法上,用于定义切入点,所谓的切入点是指对哪些连接点处进行切入增强的定义,在Spring中具体就是指对哪些方法进行切入增强的定义;被@Pointcut注解表示切入点的表达式有多种,最常用的是两种,execution表达式和注解;

Jointpoint,连接点,所谓的连接点是指被aop切面切入的位置点,在Spring中具体就是指被切入的方法;

PointCut,

Advice,通知,所谓的通知是指对定义好的切入点进行拦截后,要具体做哪些操作的定义;在Spring中就是指被@Before、@After、@AfterReturning、@AfterThrowing、@Around注解标记的方法;

标记切入点的常用方式

execution表达式

表达式请法:访问修饰符 返回值 包名.包名...类名.方法(参数列表)

示例1:表示匹配所有com.fanfu包以及子包下的所有类中以add开头的方法,返回值、参数不限;

@Pointcut("execution(* com.fanfu..*.*.add*(..))")

示例2:表示匹配所有com.fanfu包以及子包下的所有类中以add开头,参数类型是String的方法,返回值不限;

@Pointcut("execution(* com.fanfu..*.*.add*(String))")

示例3:表示匹配com.fanfu包下任意类、任意方法、任意参数;

@Pointcut("execution(* com.fanfu..*.*.*(String))")

execution()为表达式的主体;
第一个*表示返回值类型为任意,即不限制返回值类型;
包后的*表示当前包,包后面连续两个..表示当前包以及子包;
(..)表示任意参数;
最后的*.*(..)表示匹配任意类、任意方法、任意参数;

注解

注解语法:@annotation(自定义的注解)

示例:表示匹配所有标记@TestAop注解的方法;

@Pointcut("@annotation(com.fanfu.config.TestAop)")

Spring Aop的小技巧

每一个@Pointcut可以使用execution或注解来定义切入点,多个切点之间还可以使用逻辑运算符,如&&、||、!运算;

point1()&&point2()表示命中point1和point2的所有切入点的交集;如示例:com.fanfu包以及下属所有子包的所有类中,方法名是以add开头,参数类型是String的所有方法,与com.fanfu.service包以及下属所有子包的所有类中,不限方法名和参数类型的所有方法取交集,即com.fanfu.service包以及下属所有子包的所有类中,方法或是add1或add2的方法,在调用前后都会执行环绕通知around()方法内的逻辑;

@Component@Aspect@Slf4jpublic class ExampleAop {    @Pointcut("execution(* com.fanfu..*.*.add*(String))")    public void point1() {    }    @Pointcut("execution(* com.fanfu.service..*.*(..))")    public void point2() {    }    @Pointcut("point1()&&point2()")    public void point() {    }    @Around("point()")    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        log.info("------around start");        Object proceed = proceedingJoinPoint.proceed();        log.info("------around end");        return proceed;    }}

point1()&&point2()表示命中point1和point2的所有切入点的并集;如示例:com.fanfu.service包以及下属所有子包的所有类中,方法名是add1,参数类型是String的所有方法,与com.fanfu.controller包以及下属所有子包的所有类中,方法名是add2,参数类型是String的所有方法取并集,即com.fanfu.service或com.fanfu.controller的包以及下属所有子包的所有类中,方法或是add1或add2的方法,在调用前后都会执行环绕通知around()方法内的逻辑;

@Component@Aspect@Slf4jpublic class ExampleAop {    @Pointcut("execution(* com.fanfu.service..*.add*(String))")    public void point1() {    }    @Pointcut("execution(* com.fanfu.controller..*.*.add*(String))")    public void point2() {    }    @Pointcut("point1()||point2()")    public void point() {    }    @Around("point()")    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        log.info("------around start");        Object proceed = proceedingJoinPoint.proceed();        log.info("------around end");        return proceed;    }}

!point()表示命中point()的所有切入点取反,如示例:com.fanfu.service包及下属所有子包的所有类中,不是以add开头的方法,在调用前后都会执行环绕通知around()方法内的逻

@Component@Aspect@Slf4jpublic class ExampleAop {    @Pointcut("execution(* com.fanfu.service..*.add*(String))")    public void point() {    }    @Around("!point()")    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        log.info("------around start");        Object proceed = proceedingJoinPoint.proceed();        log.info("------around end");        return proceed;    }}

Spring Aop注意事项

与定义的切点匹配方法,如果在当前调用链中,方法在当前类是首次匹配则会命中,即执行相关的通知,如果当前的调用链没有结束,又在当前方法里调用了当前类的与其他切入点匹配方法,则不会再命中,即其他与切入点匹配的方法执行的时候不会再触发相关的通知;

如下示例:

当请求Http://localhost:8080/example时,ExampleController中的example方法被触发,ExampleController#example()又调用了ExampleService#test(),在ExampleService#test()内部,又顺序调用了ExampleService#test1()和ExampleService#test2();在ExampleAop中,按照execution中的配置,是可以匹配到test()、test1()、test2(),实际是命中的方法只有test();

@Component@Aspect@Slf4jpublic class ExampleAop {    @Pointcut("execution(* com.fanfu.service.impl.ExampleServiceImpl.test*(..))")    public void point2() {        log.info("切入点匹配");    }    @Around("point()")    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        log.info("------around start");        String methodName = proceedingJoinPoint.getSignature().getName();        String className = proceedingJoinPoint.getTarget().getClass().getName();        Object[] args = proceedingJoinPoint.getArgs();        String argsName=null;        StringBuilder sb=new StringBuilder();        if (args!=null&&args.length>0) {            for (int i = 0; i < args.length; i++) {                if (args[i] != null) {                    sb.append(";").append(args[i].getClass().getName());                }            }            if (sb.toString().length()>0) {                argsName=sb.toString().substring(1);            }        }        log.info("命中类:{},方法{},参数{};",className,methodName,argsName);        Object proceed = proceedingJoinPoint.proceed();        log.info("------around end");        return proceed;    }}
@Service@Slf4jpublic class ExampleServiceImpl implements IExampleService {     @Override    public String test(String msg) {        log.info("test方法被执行");        this.test1(msg);        this.test2(msg);        return msg;    }     public String test1(String msg) {        log.info("test1方法被执行");        return "msg1";    }     public String test2(String msg) {        log.info("test2方法被执行");        return "msg2";    }}
public interface IExampleService {    public String test(String msg);    public String test1(String msg);    public String test2(String msg);}
@RestController@Slf4jpublic class ExampleController {    @Autowired    private IExampleService exampleService;    @GetMapping("/example")    public String example() {        log.info("example start");        exampleService.test(null);        log.info("example end");        return String.valueOf(System.currentTimeMillis());    }}

Springboot项目如何快速实现Aop功能

对于上面的问题,如果把execution表达换成注解,会不会结果不一样?再把ExampleAop中的@Pointcut改成注解形式,再在ExampleService#test1()、ExampleService#test2()、ExampleService#test()添加注解@TestAop,验证结果依然是一样的,只有test()会命中,其他不会!所以要注意呀。

@Component@Aspect@Slf4jpublic class ExampleAop {    @Pointcut("@annotation(TestAop)")    public void point() {    }    @Around("point()")    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {        log.info("------around start");        String methodName = proceedingJoinPoint.getSignature().getName();        String className = proceedingJoinPoint.getTarget().getClass().getName();        Object[] args = proceedingJoinPoint.getArgs();        String argsName = null;        StringBuilder sb = new StringBuilder();        if (args != null && args.length > 0) {            for (int i = 0; i < args.length; i++) {                if (args[i] != null) {                    sb.append(";").append(args[i].getClass().getName());                }            }            if (sb.toString().length() > 0) {                argsName = sb.toString().substring(1);            }        }        log.info("命中类:{},方法{},参数{};", className, methodName, argsName);        Object proceed = proceedingJoinPoint.proceed();        log.info("------around end");        return proceed;    }}
@Service@Slf4jpublic class ExampleServiceImpl implements IExampleService {     @Override    @TestAop    public String test(String msg) {        log.info("test方法被执行");        this.test1(msg);        this.test2(msg);        return msg;    }    @Override    @TestAop    public String test1(String msg) {        log.info("test1方法被执行");        return "msg1";    }    @Override    @TestAop    public String test2(String msg) {        log.info("test2方法被执行");        return "msg2";    }   }

那什么情况下,ExampleService#test1()、ExampleService#test2()、ExampleService#test()会同时命中呢?让从ExampleController#example()到ExampleService#test1()、ExampleService#test2()、ExampleService#test()分别在不同的调用链上,那么就可以同时命中了;

@RestController@Slf4jpublic class ExampleController {    @Autowired    private IExampleService exampleService;    @GetMapping("/example")    public String example() {        log.info("example start");        exampleService.test(null);        exampleService.test1(null);        exampleService.test2(null);        log.info("example end");        return String.valueOf(System.currentTimeMillis());    }}

Springboot项目如何快速实现Aop功能

感谢各位的阅读,以上就是“Springboot项目如何快速实现Aop功能”的内容了,经过本文的学习后,相信大家对Springboot项目如何快速实现Aop功能这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Springboot项目如何快速实现Aop功能

本文链接: https://www.lsjlt.com/news/353662.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Springboot项目如何快速实现Aop功能
    这篇文章主要讲解了“Springboot项目如何快速实现Aop功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Springboot项目如何快速实现Aop功能”吧!依赖引入Springboo...
    99+
    2023-07-05
  • 如何快速搭建一个springboot项目
    本篇内容主要讲解“如何快速搭建一个springboot项目”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何快速搭建一个springboot项目”吧!一、空项目现在开发过程中大都是idea这个集...
    99+
    2023-06-30
  • Python如何快速生成本项目的requeirments.txt实现
    目录1.使用pipreqs生成requeirments.txt2.使用pip在Python项目中,我们通常需要使用许多第三方库来提供额外的功能和工具。但是,直接将这些库上传到Git仓...
    99+
    2023-03-14
    Python 生成本项目的requeirments.txt Python 生成requeirments.txt
  • Eclipse3.5的快速项目导航功能怎么用
    本篇内容介绍了“Eclipse3.5的快速项目导航功能怎么用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Open Declaration在...
    99+
    2023-06-17
  • Shiro在springboot中如何快速实现
    这篇“Shiro在springboot中如何快速实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Shiro在springb...
    99+
    2023-07-05
  • FastApi如何快速构建一个web项目的实现
    目录项目介绍项目目录构成项目内容数据文件内容模板渲染同步接口异步接口项目入口文件项目依赖项目部署访问效果FastApi快速构建一个web项目 已经使用FastApi很久了。这个一个...
    99+
    2023-03-24
    FastApi构建web项目 FastApi构建web
  • 怎么在Java项目中利用QuickSort实现一个快速排序功能
    今天就跟大家聊聊有关怎么在Java项目中利用QuickSort实现一个快速排序功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。快速排序-----------------------...
    99+
    2023-05-31
    quicksort java
  • idea快速实现将SpringBoot项目打包Docker镜像并部署
    目录1.修改docker的配置文件2.配置端口开放3.IDEA安装Docker插件4.IDEA配置docker5.SpringBoot整合Docker配置5.1 安装pom依赖5.2...
    99+
    2024-04-02
  • 如何使用PHP实现快速的直播功能?
    随着直播行业的不断发展,越来越多的企业开始尝试直播营销。而对于程序员来说,使用PHP实现直播功能是一个不错的选择。本文将介绍如何使用PHP实现快速的直播功能。了解直播的基本原理在开始使用PHP实现直播功能之前,我们首先应该了解直播的基本原理...
    99+
    2023-05-22
    PHP 直播功能 快速实现
  • vue3.0+vant3.0快速搭建项目的实现
    目录一、项目的搭建二、vue3体验+vant引入2020年09月18日,vue.js 3.0正式发布,去网上看了看关于3.0的教程都不够完整,但其实vuecli最新版已经支持了vue...
    99+
    2024-04-02
  • Java中如何快速构建项目脚手架的实现
    目录1 前言2 微服务项目准备3 脚手架构建3.1 项目正常启动 && 测试用例正常3.2 在项目的根pom中加入以下maven插件配置3.3 执行archetype...
    99+
    2024-04-02
  • gitee上如何快速搜索项目
    这篇文章主要讲解了“gitee上如何快速搜索项目”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“gitee上如何快速搜索项目”吧!使用Gitee的搜索框Gitee提供了一个方便的搜索框,您可以...
    99+
    2023-07-05
  • springboot vue项目管理前后端实现编辑功能
    目录基于springboot+vue 的测试平台开发一、打开编辑页面显示数据1. 编辑按钮2. 编写 handleUpdate 方法处理数据外显二、保存编辑页面的内容1. 后端增加 ...
    99+
    2024-04-02
  • 如何快速搭建spring boot2.0项目
    这篇文章主要讲解了“如何快速搭建spring boot2.0项目”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何快速搭建spring boot2.0项目”...
    99+
    2024-04-02
  • SpringBoot项目整合FastDFS+Nginx实现图片上传功能
    目录FastDFS概述Fastdfs原理安装Fastdfs整合Nginx模块安装NginxSpringBoot整合FastdfsFastDFS概述 FastDFS是一个开源的轻量级分...
    99+
    2024-04-02
  • 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能
    目录1.SpringBoot AOP功能1.1 LTW与不同的切面织入时机1.2 JDK实现LTW的原理1.3 如何在Spring中实现LTW2. Springboot中使用LTW实...
    99+
    2024-04-02
  • 如何在Java项目中实现一个快速查找算法
    如何在Java项目中实现一个快速查找算法?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。快速查找算法,可以根据想要找的是第几个大的数,每次循环都能固定下来一个数在数组完整排完序之...
    99+
    2023-05-31
    java ava 目中
  • 如何在Go语言项目中实现IOC功能
    在Go语言项目中实现控制反转(Inversion of Control,IOC)功能是一种常见的设计模式,它可以帮助我们更好地管理项目中的依赖关系,提高代码的灵活性和可维护性。本文将介...
    99+
    2024-04-02
  • Vue项目中如何实现带参跳转功能
    这篇文章主要介绍Vue项目中如何实现带参跳转功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!页面介绍:主页面:name —> shishengzuotanhuichaxun此页面表格中的数据均通过接口从后端获...
    99+
    2023-06-14
  • idea怎么快速实现将SpringBoot项目打包Docker镜像并部署
    这篇文章主要介绍了idea怎么快速实现将SpringBoot项目打包Docker镜像并部署的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇idea怎么快速实现将SpringBoot项目打包Docker镜像并部署文...
    99+
    2023-06-30
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作