乐趣区

关于aop:你不是说你会Aop吗

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

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

上面是我跟小王的次要对话。

我:说说怎么了?

小王:我将记录接口日志的性能放到了每个 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 类型

小王看到这里后,豁然开朗,筹备连忙回去试一下。我急忙拉住他。

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

小王:那我在异样告诉里解决就能够了。

我:你再想一下?

小王:如同不行,异样告诉里获取不到申请参数。

我:在盘绕告诉中捕捉解决能够吗?

这时候,看见小王眼睛发光,诧异的说了一句:盘绕告诉太牛批了,居然能够实现前置告诉、后置告诉和异样告诉的工作!

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

退出移动版