你不是说你会 Aop 吗?
一大早,小王就急匆匆的跑过来找我,说:周哥,那个记录日志的功能我想请教一下。
因为公司某个项目要跟别的平台做对接,我们这边需要给他们提供一套接口。昨天,我就将记录接口日志的工作安排给了小王。
下面是我跟小王的主要对话。
我:说说怎么了?
小王:我将记录接口日志的功能放到了每个 controller 中,现在感觉有点繁琐,我这样做是不是不太合适?
我:为什么要去每个接口里记录日志?
小王:最开始我是用的拦截器,但是这样一个请求就记录了两条记录。
我:为什么是两条?
小王:在 preHandle 中记录一条请求数据,在 postHandle 中记录一条响应数据。
我:。。。你不是说你会 Aop 吗?
小王:Aop 也是一样,在前置通知记录一条请求数据,后置通知记录一条响应数据。
小王:这个数据和以前记录操作日志的不太一样,以前只需要在前置通知记录一条操作日志就可以了,但是现在有响应,所以只能在 controller 中记录日志了。
我:那你知不知道有个环绕通知?你说一下 Aop 就几种通知类型。
小王:总共有五种,分别是:
前置通知:在我们执行目标方法之前运行(@Before)
后置通知:在我们目标方法运行结束之后,不管有没有异常(@After)
返回通知:在我们的目标方法正常返回值后运行(@AfterReturning)
异常通知:在我们的目标方法出现异常后运行(@AfterThrowing)
环绕通知:目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,joinPoint.procced()就是执行目标方法的代码 。环绕通知可以控制返回对象(@Around)
接下来,我们一起来演示一下如何使用环绕通知来解决小王的问题。
第一步:提供接口用来接收参数和响应接口
第二步:定义切点
execution()是比较常用的定义切点的表达式,execution()语法如下:
其中:
修饰符和 throws 异常可以省略不写
根据这些解释,我们可以将第一步中的接口用 execution()表达式来描述一下:
*
:匹配所有项
..
:匹配任意个方法参数..
出现在类名中时,后面必须跟*
,表示包、子孙包下的所有类;
现在我们优化一下上面的表达式,定义切面为 controller 包及 controller 下面所有包的所有方法
第三步:环绕通知记录日志
运行结果如下:
我们之所以可以用环绕通知来处理小王的问题。其中一个重要的原因就是,我们提供的所有接口都是经过统一加密的,最后请求的参数都是一个固定的名字。还需要注意的一点就是,环绕通知的返回值类型必须大于等于方法的返回值,即:加入你方法返回 String 类型,环绕通知不能写成 void 类型。
小王看到这里后,恍然大悟,准备赶紧回去试一下。我急忙拉住他。
我:如果接口出现异常了怎么办?
小王:那我在异常通知里处理就可以了。
我:你再想一下?
小王:好像不行,异常通知里获取不到请求参数。
我:在环绕通知中捕获处理可以吗?
这时候,看见小王眼睛发光,惊讶的说了一句:环绕通知太牛批了,竟然可以完成前置通知、后置通知和异常通知的工作!
这篇文章戏有点多,别见怪。实战是提升技术最有效的途径!
版权声明: 本文为 InfoQ 作者【Java旅途】的原创文章。
原文链接:【http://xie.infoq.cn/article/1653722e02d98f5c2afc7b3d6】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论