一大早,小王就急匆匆的跑过来找我,说:周哥,那个记录日志的功能我想请教一下。

因为公司某个项目要跟别的平台做对接,我们这边需要给他们提供一套接口。昨天,我就将记录接口日志的工作安排给了小王。

下面是我跟小王的主要对话。

我:说说怎么了?

小王:我将记录接口日志的功能放到了每个controller中,现在感觉有点繁琐,我这样做是不是不太合适?

我:为什么要去每个接口里记录日志?

小王:最开始我是用的拦截器,但是这样一个请求就记录了两条记录。

我:为什么是两条?

小王:在preHandle中记录一条请求数据,在postHandle中记录一条响应数据。

我:。。。你不是说你会Aop吗?

小王:Aop也是一样,在前置通知记录一条请求数据,后置通知记录一条响应数据。

小王:这个数据和以前记录操作日志的不太一样,以前只需要在前置通知记录一条操作日志就可以了,但是现在有响应,所以只能在controller中记录日志了。

我:那你知不知道有个环绕通知?你说一下Aop就几种通知类型。

小王:总共有五种,分别是:

  • 前置通知:在我们执行目标方法之前运行(@Before
  • 后置通知:在我们目标方法运行结束之后,不管有没有异常(@After
  • 返回通知:在我们的目标方法正常返回值后运行(@AfterReturning
  • 异常通知:在我们的目标方法出现异常后运行(@AfterThrowing
  • 环绕通知:目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,joinPoint.procced()就是执行目标方法的代码 。环绕通知可以控制返回对象(@Around)

接下来,我们一起来演示一下如何使用环绕通知来解决小王的问题。

第一步:提供接口用来接收参数和响应接口

@RestController
public class TestController {
@GetMapping("/getName")
public String getName(HttpServletRequest request) throw Exception { String result = "Java旅途";
String age = request.getParameter("age");
if("18".equals(age)){
result = "无法识别";
}
return result;
}
}

第二步:定义切点

execution()是比较常用的定义切点的表达式,execution()语法如下:

execution(修饰符  返回值  包.类.方法名(参数) throws异常)

其中:

修饰符和throws异常可以省略不写

根据这些解释,我们可以将第一步中的接口用execution()表达式来描述一下:

execution(String binzh.website.controller.TestController.GetName(HttpServletRequest))
  • *:匹配所有项

  • ..:匹配任意个方法参数

  • ..出现在类名中时,后面必须跟*,表示包、子孙包下的所有类;

现在我们优化一下上面的表达式,定义切面为controller包及controller下面所有包的所有方法

execution(* binzh.website.controller..*.*(..))

第三步:环绕通知记录日志

@Around("execution(* binzh.website.controller..*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String age = request.getParameter("age");
Object proceed = "";
try {
proceed = joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("age==="+age);
System.out.println("proceed ===="+proceed);
return proceed;
}

运行结果如下:

age===19
proceed ====Java旅途

我们之所以可以用环绕通知来处理小王的问题。其中一个重要的原因就是,我们提供的所有接口都是经过统一加密的,最后请求的参数都是一个固定的名字。还需要注意的一点就是,环绕通知的返回值类型必须大于等于方法的返回值,即:加入你方法返回String类型,环绕通知不能写成void类型

小王看到这里后,恍然大悟,准备赶紧回去试一下。我急忙拉住他。

我:如果接口出现异常了怎么办?

小王:那我在异常通知里处理就可以了。

我:你再想一下?

小王:好像不行,异常通知里获取不到请求参数。

我:在环绕通知中捕获处理可以吗?

这时候,看见小王眼睛发光,惊讶的说了一句:环绕通知太牛批了,竟然可以完成前置通知、后置通知和异常通知的工作!

这篇文章戏有点多,别见怪。实战是提升技术最有效的途径!

你不是说你会Aop吗?的更多相关文章

  1. 基于spring注解AOP的异常处理

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...

  2. Spring基于AOP的事务管理

                                  Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...

  3. 学习AOP之透过Spring的Ioc理解Advisor

    花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...

  4. 学习AOP之深入一点Spring Aop

    上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...

  5. 学习AOP之认识一下Spring AOP

    心碎之事 要说知道AOP这个词倒是很久很久以前了,但是直到今天我也不敢说非常的理解它,其中的各种概念即抽象又太拗口. 在几次面试中都被问及AOP,但是真的没有答上来,或者都在面上,这给面试官的感觉就是 ...

  6. .Net中的AOP系列之构建一个汽车租赁应用

    返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...

  7. .NET里简易实现AOP

    .NET里简易实现AOP 前言 在MVC的过滤器章节中对于过滤器的使用就是AOP的一个实现了吧,时常在工作学习中遇到AOP对于它的运用可以说是很熟练了,就是没想过如果自己来实现的话是怎么实现的,性子比 ...

  8. 在.Net中实现自己的简易AOP

    RealProxy基本代理类 RealProxy类提供代理的基本功能.这个类中有一个GetTransparentProxy方法,此方法返回当前代理实例的透明代理.这是我们AOP实现的主要依赖. 新建一 ...

  9. 使用Java原生代理实现AOP

    ### 本文由博主柒.原创,转载请注明出处 ### 完整源码下载地址 [https://github.com/MatrixSeven/JavaAOP](https://github.com/Matri ...

  10. 【开源】.Net Aop(静态织入)框架 BSF.Aop

    BSF.Aop .Net 免费开源,静态Aop织入(直接修改IL中间语言)框架,类似PostSharp(收费): 实现前后Aop切面和INotifyPropertyChanged注入方式. 开源地址: ...

随机推荐

  1. True Liars POJ - 1417

    True Liars After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was f ...

  2. day04 python入门(变量,基本数据类型)

    python入门学习 来自egon的学习套路 在每次遇到一个新事物的时候,要学三步: xxx是什么? 为什么要有xxx? ​ 大前提:python中所有出现的语法都是为了让计算机能够具有人的某一个功能 ...

  3. 一、python 基础之基础语法

    一.变量命名规则 1.驼峰命名 大驼峰 MyName = 'leon' 小驼峰 myName = 'Amy' 2.下划线命名 my_name = 'jack' 建议:变量名或者文件名使用下划线命名方式 ...

  4. JVM 专题三:类加载子系统(一)类装载器子系统

    类装载器子系统 1.1 什么是类装载子系统? 类装载器子系统负责从文件系统或者网络中加载Class文件,Class文件在文件开头有特定的文件标识(魔数). 类装载器子系统(ClassLoader)只负 ...

  5. java 面向对象(三十六):泛型五 通配符

    1.通配符的使用 /* 通配符的使用 通配符:? 类A是类B的父类,G<A>和G<B>是没关系的,二者共同的父类是:G<?> */ @Test public voi ...

  6. How to install nginx in Ubuntu

    The steps for installing the nginx on Ubuntu below. 1.install the packages first. apt-get install gc ...

  7. 你应该知道的ip地址相关知识

    IP地址是一个网卡在网络世界里的通讯地址,相当于我们家里的门牌号码.这样类比的话,很显然ip地址是唯一的.在windows系统中,我们可以使用 ipconfig 命令查看本机的ip地址相关信息: 图中 ...

  8. Gradle系列之构建脚本基础

    原文发于微信公众号 jzman-blog,欢迎关注交流. 前面两篇文章分别介绍了 Gradle 基础知识以及 Groovy 相关基础知识,这也是学习 Gradle 所必需了解的,文章链接如下:: Gr ...

  9. 资深CIO介绍如何选型OA系统的?

    OA办公系统成为企业管理的标配软件,在于可有效加强组织管理能力,提高员工协同效率,助力企业科学决策,合理分配企业资源,提升企业综合实力与市场竞争力.企业OA选型的经验总结来说也就是品牌.技术.产品.服 ...

  10. .Net Core in Docker极简入门(上篇)

    目录 前言 开始 环境准备 Docker基础概念 Docker基础命令 Docker命令实践 构建Docker镜像 Dockerfile bulid & run 前言 Docker 是一个开源 ...