广州网站建设培训wordpress调用最新文章插件
news/
2025/9/27 8:16:27/
文章来源:
广州网站建设培训,wordpress调用最新文章插件,机电工程东莞网站建设技术支持,怎么推广小程序Spring AOP实现 AOP概述什么是AOP什么是Spring AOP Spring AOP快速入门引入依赖实现计时器 Spring AOP详解Spring AOP核心概念切点(Pointcut)连接点(Join Point)通知(Advice)切面(Aspect) 通知类型注意事项 PointCut多个切面切面优先级 Order切点表达式execution表达式annotati… Spring AOP实现 AOP概述什么是AOP什么是Spring AOP Spring AOP快速入门引入依赖实现计时器 Spring AOP详解Spring AOP核心概念切点(Pointcut)连接点(Join Point)通知(Advice)切面(Aspect) 通知类型注意事项 PointCut多个切面切面优先级 Order切点表达式execution表达式annotation AOP概述 什么是AOP
Aspect Oriented Programming面向切面编程) 什么是面向切面编程,切面指的是某一类特定的问题,所以AOP也可以理解为面向特定方法的编程 简单来说:AOP是一种思想,是对某一类问题的集中处理
什么是Spring AOP
AOP是一种思想,它的实现方法有很多,其中包括Spring AOP也有AspectJ、CGLIB等
Spring AOP快速入门
引入依赖
在pom.xml文件中添加配置
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-aop/artifactId
/dependency实现计时器
这里我通过一个AOP的实现来记录程序中各个函数执行的时间
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;Slf4j
Aspect
Component
public class TimeAspect {Around(execution(* com.example.demo.controller.*.*(..)))public Object timeCost(ProceedingJoinPoint joinPoint) throws Throwable {long start System.currentTimeMillis();Object result joinPoint.proceed();long end System.currentTimeMillis();log.info(joinPoint消耗时间:{},end-startms);return result;}
}执行上述代码 我们来分析一些这段代码 这个注解,表明当前类是一个切面类 这个注解,将该段程序交给spring来管理 环绕通知,在目标方法的前后都会被执行.后面的表达式表示对哪些方法进行增强 表示当前需要执行的方法 表示开始执行当前的方法 上面代码就解析完成了,接下来,我们开始正式学习AOP的知识
Spring AOP详解
Spring AOP核心概念
切点(Pointcut)
Pointcut的作用就是提供⼀组规则(使用AspectJ pointcut expression language 来描述), 告诉程序对哪些方法来进行功能增强. Around注解里面的就是切入点的表达式
连接点(Join Point)
满足切点表达式规则的方法, 就是连接点. 也就是可以被AOP控制的方法,以入门程序举例, 所有 com.example.demo.controller 路径下的方法, 都是连接点. 切点和连接点的关系 连接点是满足切点表达式的元素. 切点可以看做是保存了众多连接点的⼀个集合
通知(Advice)
通知就是具体要做的工作, 指哪些重复的逻辑也就是共性功能(最终体现为一个方法)比如上述程序中记录业务方法的耗时时间, 就是通知
切面(Aspect)
切⾯(Aspect) 切点(Pointcut) 通知(Advice),既是整个程序
通知类型
上面我们讲了什么是通知, 接下来学习通知的类型. Around 就是其中⼀种通知类型, 表示环绕通知. Spring中AOP的通知类型有以下几种 • Around: 环绕通知, 此注解标注的通知方法在目标方法前, 后都被执行 • Before: 前置通知, 此注解标注的通知方法在目标方法前被执行 • After: 后置通知, 此注解标注的通知方法在目标方法后被执行, 无论是否有异常都会执行 • AfterReturning: 返回后通知, 此注解标注的通知方法在目标方法后被执行, 有异常不会执行 • AfterThrowing: 异常后通知, 此注解标注的通知方法发生异常后执行 接下来.我们通过程序来进行学习
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
Slf4j
Aspect
Component
public class AspectDemo {Before(execution(* com.example.demo.controller.*.*(..)))public void doBefore(){log.info(执行AspectDemo doBefore);}After(execution(* com.example.demo.controller.*.*(..)))public void doAfter(){log.info(执行AspectDemo doAfter);}AfterReturning(execution(* com.example.demo.controller.*.*(..)))public void doAfterReturning(){log.info(doAfterReturning);}AfterThrowing(execution(* com.example.demo.controller.*.*(..)))public void doAfterThrowing(){log.info(doAfterThrowing);}Around(execution(* com.example.demo.controller.*.*(..)) )public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info(doAround 前);Object result joinPoint.proceed();log.info(doAround 后);return result;}
}
package com.example.demo.controller;import com.example.demo.aspect.MyAspect;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;Slf4j
RestController
public class HelloController {RequestMapping(/t1)public String helloTest(){return t1;}RequestMapping(/t2)public String testError(){Integer i 10/0;return t2;}
}我们运行程序,我们通过访问t1的url来执行t1的程序 可以看到,各个注解执行的时间顺序是不一样的 而在程序正常的情况下,AfterThrowing的通知并没有执行 那么接下来,我们来访问t2的url 结果是出现报错了,我们跳过程序打印的错误日志,可以看到 执行结果变成了四个
注意事项
• Around 环绕通知需要调用ProceedingJoinPoint.proceed() 来让原始方法执行, 其他通知不需要考虑目标方法执行. • Around 环绕通知方法的返回值, 必须指定为Object, 来接收原始方法的返回值, 否则原始方法执行完毕, 是获取不到返回值的,而且Around必须要有返回值
PointCut
上面代码存在⼀个问题, 就是存在大量重复的切点表达式 execution(* com.example.demo.controller..(…)) , Spring提供了 PointCut 注解, 把公共的切点表达式提取出来, 需要用到时引用该切入点表达式即可. 下面我们来讲讲怎么使用
Pointcut(execution(* com.example.demo.controller.*.*(..)))public void pointcut(){}这里的方法名可以随意取 定义完成,怎么使用呢 我们只需要将pointcut()把其他通知里的切入点表达式给替换掉就行了
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
Slf4j
Aspect
Component
public class AspectDemo {Pointcut(execution(* com.example.demo.controller.*.*(..)))public void pointcut(){}Before(pointcut())public void doBefore(){log.info(执行AspectDemo doBefore);}After(pointcut())public void doAfter(){log.info(执行AspectDemo doAfter);}AfterReturning(pointcut())public void doAfterReturning(){log.info(doAfterReturning);}AfterThrowing(pointcut())public void doAfterThrowing(){log.info(doAfterThrowing);}Around(pointcut() )public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info(doAround 前);Object result joinPoint.proceed();log.info(doAround 后);return result;}
}
这样就好啦,如果需要在其他切面中使用该切入点的定义时,需要将方法的修饰改为public,同时需要在切入点表达式中,在pointcut()前加上全限定类名,引用方式为: 全限定类名.方法名()
多个切面
我们创建多个切面类,观察一些结果
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
Slf4j
Aspect
Component
public class AspectDemo1 {Before(com.example.demo.aspect.AspectDemo.pt())public void doBefore(){log.info(执行AspectDemo1 doBefore);}After(com.example.demo.aspect.AspectDemo.pt())public void doAfter(){log.info(执行AspectDemo1 doAfter);}
}
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
Slf4j
Aspect
Component
public class AspectDemo2 {Before(com.example.demo.aspect.AspectDemo.pt())public void doBefore(){log.info(执行AspectDemo2 doBefore);}After(com.example.demo.aspect.AspectDemo.pt())public void doAfter(){log.info(执行AspectDemo2 doAfter);}
}
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
Slf4j
Aspect
Component
public class AspectDemo3 {Before(com.example.demo.aspect.AspectDemo.pt())public void doBefore(){log.info(执行AspectDemo3 doBefore);}After(com.example.demo.aspect.AspectDemo.pt())public void doAfter(){log.info(执行AspectDemo3 doAfter);}
}
执行程序,访问t1 从执行结果可以看出,如果程序中有多个切面,执行顺序是依据切面类的名字来执行的 存在多个切面类时,默认按照切面类的类名字母排序 • Before 通知字母排名靠前的先执行 • After 通知字母排名靠前的后执行
切面优先级 Order
对于多个切面的情况,我们可以利用 Order来控制他们执行的顺序 执行程序,观察结果 很明显,执行结果如愿得到了优化 Order 注解标识的切面类, 执行顺序如下: • Before 通知数字越小先执行 • After 通知数字越大先执行
切点表达式
上面的代码中, 我们⼀直在使用切点表达式来描述切点. 下面我们来介绍⼀下切点表达式的语法. 切点表达式常见有两种表达方式
execution(……)根据方法的签名来匹配annotation(……) 根据注解匹配
execution表达式
execution(访问修饰符 返回类型 包名.类名.方法(方法参数) 异常) 其中:访问修饰符和异常可以省略 切点表达式⽀持通配符表达:
* 匹配任意字符只匹配⼀个元素(返回类型, 包, 类名, 方法或者方法参数) a. 包名使用* 表示任意包(⼀层包使用⼀个*) b. 类名使用* 表示任意类 c. 返回值使用* 表示任意返回值类型 d. ⽅法名使用* 表示任意方法 e. 参数使用* 表示⼀个任意类型的参数… 匹配多个连续的任意符号, 可以通配任意层级的包, 或任意类型, 任意个数的参数 a. 使用… 配置包名标识此包以及此包下的所有子包 b. 可以使用… 配置参数任意个任意类型的参数
annotation
首先,我们先自定义一个注解(其他已有的注解也可以)
package com.example.demo.aspect;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Retention(RetentionPolicy.RUNTIME)
Target({ElementType.METHOD})
public interface MyAspect {}
在我们需要实现功能增强的连接点(方法)上添加我们刚刚创建的注解 这里我们在t1上添加 然后我们可以再创建一个切面类
package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;Slf4j
Aspect
Component
public class MyAspectDemo {Before(annotation(com.example.demo.aspect.MyAspect))public void doBefore(){log.info(MyAspectDemo doBefore);}After(annotation(com.example.demo.aspect.MyAspect))public void doAfter(){log.info(MyAspectDemo doAfter);}
}可以看到,代码中,我们的切入点表达式格式是 annotation(注解的全限定类名注解名) 接下来,我们执行程序,注意,这里需要屏蔽其他切面的影响 访问t1 程序执行成功了 然后我们执行t2 可以看到,日志并没有t2的相关结果 那么到这里,AOP的使用,我就分享完了,感谢大家的支持
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/916742.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!