Spring AOP详解一文搞懂@Aspect、@Pointcut、@Before、@Around、@After、@AfterReturning、@AfterThrowing
文章目录
- 1、AOP是什么
- 2、AOP中注解的含义
- 3、Pointcut切入点的语法
- 4、AOP代码实现
1、AOP是什么
AOP:Aspect Oriented Programming,翻译过来就是大名鼎鼎的“面向切面编程”,它是对面向对象的一种补充和完善。
AOP的使用场景一般有:数据源切换、事务管理、权限控制、日志打印等。根据它的名字我们不难理解,它的实现很像是将我们要实现的代码切入业务实现的逻辑中。它有以下特点:
1、侵入性小,几乎可以不改动原来逻辑的情况下把新的逻辑加入业务。
2、实现方便,使用几个注解就可以实现,使系统更容易扩展。
3、更好的复用代码,比如事务日志打印,简单逻辑适合所有情况。
相关代码请参考: chapter-4-springmvc-sourcecode-analysis
https://gitee.com/leo825/spring-framework-learning-example.git
2、AOP中注解的含义
@Aspect
:切面。表示一个横切进业务的一个对象。它里面包含切入点(Pointcut)和Advice(通知)。
@Pointcut
:切入点。表示需要切入的位置,比如某些类或者某些方法,也就是先定一个范围。
@Before
:Advice(通知)的一种,切入点的方法体执行之前执行。
@Around
:Advice(通知)的一种,环绕切入点执行也就是把切入点包裹起来执行。
@After
:Advice(通知)的一种,在切入点正常运行结束后执行。
@AfterReturning
:Advice(通知)的一种,在切入点正常运行结束后执行,异常则不执行
@AfterThrowing
:Advice(通知)的一种,在切入点运行异常时执行。
3、Pointcut切入点的语法
语法规则如下代码中注释所示:
/*** 1、使用within表达式匹配* 下面示例表示匹配com.leo.controller包下所有的类的方法*/@Pointcut("within(com.leo.controller..*)")public void pointcutWithin(){}/*** 2、this匹配目标指定的方法,此处就是HelloController的方法*/@Pointcut("this(com.leo.controller.HelloController)")public void pointcutThis(){}/*** 3、target匹配实现UserInfoService接口的目标对象*/@Pointcut("target(com.leo.service.UserInfoService)")public void pointcutTarge(){}/*** 4、bean匹配所有以Service结尾的bean里面的方法,* 注意:使用自动注入的时候默认实现类首字母小写为bean的id*/@Pointcut("bean(*ServiceImpl)")public void pointcutBean(){}/*** 5、args匹配第一个入参是String类型的方法*/@Pointcut("args(String, ..)")public void pointcutArgs(){}/*** 6、@annotation匹配是@Controller类型的方法*/@Pointcut("@annotation(org.springframework.stereotype.Controller)")public void pointcutAnnocation(){}/*** 7、@within匹配@Controller注解下的方法,要求注解的@Controller级别为@Retention(RetentionPolicy.CLASS)*/@Pointcut("@within(org.springframework.stereotype.Controller)")public void pointcutWithinAnno(){}/*** 8、@target匹配的是@Controller的类下面的方法,要求注解的@Controller级别为@Retention(RetentionPolicy.RUNTIME)*/@Pointcut("@target(org.springframework.stereotype.Controller)")public void pointcutTargetAnno(){}/*** 9、@args匹配参数中标注为@Sevice的注解的方法*/@Pointcut("@args(org.springframework.stereotype.Service)")public void pointcutArgsAnno(){}/*** 10、使用excution表达式* execution(* modifier-pattern? //用于匹配public、private等访问修饰符* ret-type-pattern //用于匹配返回值类型,不可省略* declaring-type-pattern? //用于匹配包类型* name-pattern(param-pattern) //用于匹配类中的方法,不可省略* throws-pattern? //用于匹配抛出异常的方法* )** 下面的表达式解释为:匹配com.leo.controller.HelloController类中以hello开头的修饰符为public返回类型任意的方法*/@Pointcut(value = "execution(public * com.leo.controller.HelloController.hello*(..))")public void pointCut() {}
需要注意:上面的匹配的类型中支持或(||)与(&&)非(!)运算。
4、AOP代码实现
首先配置pox.xml进行注解jar包的支持
<!-- aop aspect注解导包--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.9</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version></dependency>
然后在配置文件中启动注解支持,例如我的是myspringmvc-servlet.xml文件,这里需要注意的是注解要跟配置文件在一块,举个例子:如果需要切入Controller的配置就需要在myspringmvc-servlet.xml中添加,如果是切入应用的配置如Service则需要在applicationContext.xml中添加。
<!-- 开启Aop注解 --><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
Aop核心代码如下:
ThreadLocal<Long> startTime = new ThreadLocal<>();/*** 10、使用excution表达式* execution(* modifier-pattern? //用于匹配public、private等访问修饰符* ret-type-pattern //用于匹配返回值类型,不可省略* declaring-type-pattern? //用于匹配包类型* name-pattern(param-pattern) //用于匹配类中的方法,不可省略* throws-pattern? //用于匹配抛出异常的方法* )** 下面的表达式解释为:匹配com.leo.controller.HelloController类中以hello开头的修饰符为public返回类型任意的方法*/@Pointcut(value = "execution(public * com.leo.controller.HelloController.hello*(..))")public void pointCut() {}/*** 在方法执行之前执行** @param joinPoint*/@Before(value = "pointCut()")public void beforeLog(JoinPoint joinPoint) {System.out.println("进入LogAop的beforeLogger");startTime.set(System.currentTimeMillis());}/*** 在进入类之前执行,然后返回pjp.proceed()之前执行before,再执行方法体,在到after** @param*/@Around(value = "pointCut()")public Object aroundLog(ProceedingJoinPoint pjp) throws Throwable {System.out.println("进入LogAop的aroundLogger");return pjp.proceed();}/*** 在方法执行返回之后执行*/@After(value = "pointCut()")public void afterLog() {System.out.println("进入LogAop的afterLogger");long start = startTime.get();System.out.println("方法体执行耗时:" + (System.currentTimeMillis() - start) + "ms");startTime.remove();}/*** 在返回之后执行* @param o*/@AfterReturning(value = "pointCut()",returning = "o")public void afterRunningLog(Object o){System.out.println("进入LogAop的afterRunningLog");System.out.println(o.getClass());}/*** 在产生异常时执行*/@AfterThrowing(value = "pointCut()")public void afterThrowingLog(){System.out.println("进入LogAop的afterThrowingLog");}
开启debug模式,查看各个标签执行顺序;
1、断点进入@Around位置
2、执行完pjp.proceed()之后,开始进入@Before方法
3、执行完@Before中的方法后进入主方法
4、执行完主方法体,又回到了@Around的返回值
5、然后开始执行@After中内容
6.最后到了@AfterReturning方法体中
所以,正常的执行顺序是:@Around ->@Before->主方法体->@Around中pjp.proceed()->@After->@AfterReturning
如果存下异常那执行顺序是什么呢?以下模拟了一个异常。
1、首先进入了@Around的方法
2、进入了@After的方法
3、最后进入了@AfterThrowing的方法
因此如果异常在Around中pjp.proceed()之前,则执行顺序为:@Around -> @After -> @AfterThrowing
同理,如果异常在Around中pjp.proceed()之后,则执行顺序为@Around ->@Before->主方法体->@Around中pjp.proceed()->@After->@AfterThrowing*
Spring AOP详解一文搞懂@Aspect、@Pointcut、@Before、@Around、@After、@AfterReturning、@AfterThrowing相关推荐
- 标准差详解-一文搞懂标准差的含义
标准差详解-一文搞懂标准差的含义 转载自 样本标准差的意义是什么? 的第一个回答
- Spring AOP详解(转载)所需要的包
上一篇文章中,<Spring Aop详解(转载)>里的代码都可以运行,只是包比较多,中间缺少了几个相应的包,根据报错,几经百度搜索,终于补全了所有包. 截图如下: 在主测试类里面,有人怀疑 ...
- Spring AOP详解(http://sishuok.com/forum/posts/list/281.html)
三6.5 AspectJ切入点语法详解 6.5.1 Spring AOP支持的AspectJ切入点指示符 切入点指示符用来指示切入点表达式目的,,在Spring AOP中目前只有执行方法这一个连接 ...
- spring aop详解
1.前言 spring aop是一个面向切面的编程,在自己第一遍学习的时候,感觉aop没有什么作用,但是真实接触下来,感觉spring aop还是很有用途的,感觉自己之前的想法太年轻了. 2.概念 S ...
- python协程详解_彻底搞懂python协程-第一篇(关键词1-4)
任何复杂的概念或系统都不是凭空出现的,我们完全可以找到它的演化历程,寻根究底终会发现,其都是在一系列并不那么复杂的简单组件上发展演化而来! by 落花僧 本文通过一系列关键概念,逐步递进理解协程. 0 ...
- 细说Spring——AOP详解(AOP概览)
一.对AOP的初印象 首先先给出一段比较专业的术语(来自百度): 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方 式和运行期动态代理实 ...
- SpringBoot—集成AOP详解(面向切面编程Aspect)
关注微信公众号:CodingTechWork,一起学习进步. AOP介绍 AOP概述 AOP是Aspect-Oriented Programming,即为面向(切面)方面编程.在维基百科中的解释: ...
- dbcp连接池配置详解_重学MySQL:事务与连接池,一文详解带你搞懂
拼多多三面惨败,java中间件.数据库与spring框架,答不上... 吊打MySQL:21性能优化实践+学习导图+55面试+笔记+20高频知识点 Mysql事务 事务: 事务指逻辑上的一组操作,组成 ...
- ANSI、GBK、Unicode等等iconv转换详解一文搞定
本文首发于公众号"嵌入式软件实战派",关注后获得更多精品干货. > 网页上的编码 也许你会问,自从有了互联网,全世界都近在咫尺,那么网页上的编码时什么,是怎么做到不同语言文字 ...
最新文章
- jq 修改swal的标题_js-jquery-SweetAlert【一】使用
- caffe显示特征图
- 分布式数据库切分规则介绍
- 「后端小伙伴来学前端了」Vue中全局事件总线(GlobalEventBus)原理及探究过程
- 「递归」第2集 | 变得了魔术,解得了高数,这届鹅厂程序员有点酷
- elasticsearch 6.x (五) 单一文档 API 介绍和使用 update和delete API
- 【Git】Git提交代码到GitHub的基本操作流程
- 企业之haproxy
- float的比较要慎重
- Mybatis学习笔记-一级缓存与二级缓存
- 开启cdn后无法显示字体图标——CDN服务器跨域问题
- 终于理解你的软件 搞那么多年了 (通用权限管理系统组件源码完善了7-8年)
- 《21天学通Java(第7版)》——VC程序员的学习笔记1
- 网络工程师考试串讲视频教程
- css空心三角形_CSS实现空心三角指示箭头
- 计算机是uefi启动 不能装win7,UEFI引导GPT安装win7方法
- ESXi 6 升级到ESXi 6.5VIB冲突问题
- java大写英文字母_输出一个字符串中的大写英文字母数,小写英文字母数以及非英文字母(.java)...
- 线程生命周期及六种状态
- GTN Yan LeCun 1998 文章中的一步
热门文章
- SAP SMW0 上传EXCEL模板遇到的问题
- POPUP_TO_CONFIRM_LOSS_OF_DATA
- 除了收割票房,内战中的中国喜剧电影到底在拼什么?
- Java yield详解_Java 中的 yield 关键字
- linux查看telnet进程,SuseLinux上配置Telnet服务,重启xinetd守护进程时的异常
- linux pdf转换swf,CENTOS 5 PDF转换为SWF
- Python 常用排序Demo|冒、插、快、希等入门算法
- 打印 Python 的一切 —— pprint beeprint
- Python: 大型数组运算
- Python集合list,tuple,dict,set