记录请求的耗时(拦截器、过滤器、aspect)

记录请求的耗时(拦截器、过滤器、aspect)

文章前言

记录控制器请求的耗时处理通常有三种实现方式,分别是:过滤器、拦截器、aspect;下文将逐一实现。

 

1、Filter 过滤器

1.1、方法说明

需要实现 Filter 类,主要涉及三个方法:
  1. destory:销毁
  2. doFilter:处理过滤器逻辑
  3. init:filter 初始化时调用

1.2、代码部分

@Component //表明作为spring的一个bean
public class TimeFilter implements Filter {@Overridepublic void destroy() {System.out.println("time filter destroy");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("time filter start");long start = new Date().getTime();//过滤器主要逻辑,整个处理流程
        chain.doFilter(request, response);System.out.println("time filter 耗时:"+ (new Date().getTime() - start));System.out.println("time filter finish");}@Overridepublic void init(FilterConfig arg0) throws ServletException {System.out.println("time filter init");}}

1.3、补充说明

通过过滤器拦截请求的方式,有一个问题,只能拿到 http 的请求和响应(request、response),意味着只能在请求或者响应里获取一些参数;
但是当前请求到底是哪个控制器的哪个方法处理的,在filter里是无法获取的,因为实现的 Filter 这个接口是由javax(j2e)定义的,
而我们要拦截的控制器(Controller)中的请求是springmvc定义的,所以 Filter 是无法获取 spring 相关信息。 
带出下一个主角,Interceptor 拦截器,springmvc 提供。

2、Interceptor 拦截器

2.1、方法说明

需要实现 HandlerInterceptor 类,主要涉及三个方法:
  1. preHandle:请求方法之前被调用;
  2. postHandle:控制器处理方法之后会被调用,前提是没有抛出异常,抛出异常不会调用;
  3. afterCompletion:请求方法之后被调用,该方法总会被调用,如果出现了异常,将被封装到Exception对象中。

2.2、代码部分

@Component
public class TimeInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("preHandle");System.out.println(((HandlerMethod)handler).getBean().getClass().getName());System.out.println(((HandlerMethod)handler).getMethod().getName());request.setAttribute("startTime", new Date().getTime());return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("postHandle");Long start = (Long) request.getAttribute("startTime");System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("afterCompletion");Long start = (Long) request.getAttribute("startTime");System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));System.out.println("ex is "+ex);}}

2.3、补充部分

interceptor 其实等价于将 filter  doFilter() 方法中的 chain.doFilter(request, response) 分成两部分:preHandle() 、 postHandle() 
interceptor比 filter 的优势在于方法上多了另外一个参数,Object handler 该参数是用来处理当前 request 请求的控制器方法的声明;
意味着,你可以通过该参数获取当前控制器相关的信息,如控制器名称、请求的方法名。

2.4、注意部分

interceptor 跟 Filter 不一样,光声明一个 @Component 是无法达到拦截器起作用,还需要一些额外的配置。
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {@SuppressWarnings("unused")@Autowiredprivate TimeInterceptor timeInterceptor;// 拦截器的一个注册器
    @Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(timeInterceptor);}}
这个配置类需要继承 WebMvcConfigurerAdapter,并重写添加拦截器的方法 addInterceptors,将自定义拦截器添加到应用中。
这时候拦截器就生效了。 

2.5、继续补充

拦截器会拦截所有控制器里的方法调用。但是却有一个缺陷,其无法获取前端访问方法的时候所携带的参数的。
为什么会这么说?
从Spring MVC 的 DispatcherServlet 的源代码中可以发现,找到 doDispatch() 方法,也就是请求分发的方法,有一段代码如下:
如果我们自定的 Interceptor 的 preHandler 方法返回的是 false,分发任务就会截止,不再继续执行下面的代码,
而下面的一行代码正是将前端携带的参数进行映射的逻辑,也就是说,preHandler 方法不会接触到前端携带来的参数,也就是说拦截器无法处理参数。
所以这里引进 AOP 进行拦截。

3、Aspect

描述AOP常用的一些术语有:通知(Adivce)、连接点(Join point)、切点(Pointcut)、切面(Aspect)、引入(Introduction)、织入(Weaving)
首先明确的核心概念:切面 = 切点 + 通知。

3.1、通知(Adivce)

通知分为五种类型:
Before(前置通知):在目标方法被调用之前调用通知功能
After(后置通知):在目标方法完成后调用通知,无论方法是否执行成功,不会关心方法的输出是什么
After-returning(返回通知):在目标方法成功执行之后调用通知
After-throwing(异常通知):在目标方法抛出异常后调用通知
Around(通知环绕):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

3.2、连接点(Join point)

连接点是一个应用执行过程中能够插入一个切面的点。
比如:方法调用、方法执行、字段设置/获取、异常处理执行、类初始化、甚至是for循环中的某个点。
理论上, 程序执行过程中的任何时点都可以作为作为织入点, 而所有这些执行时点都是Joint point,
但 Spring AOP 目前仅支持方法执行 (method execution)。

3.3、切点(Pointcut)

通知(advice)定义了切面何时,那么切点就是定义切面“何处” 描述某一类 Joint points, 
比如定义了很多 Joint point, 对于 Spring AOP 来说就是匹配哪些方法的执行。

3.4、切面(Aspect)

切面是切点和通知的结合。通知和切点共同定义了关于切面的全部内容 —— 它是什么时候,在何时和何处完成功能。

3.5、引入(Introduction)

引用允许我们向现有的类添加新的方法或者属性

3.6、织入(Weaving)

组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。
Spring和其他纯Java AOP框架一样,在运行时完成织入。

 


 

来看一下 Aspect 怎么写:
@Aspect
@Component
public class TimeAspect {@Around("execution(* club.sscai.security.web.controller.UserController.*(..))")public Object handleTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("time aspect is start.");for (Object object : proceedingJoinPoint.getArgs()) {System.out.println(object);}long startTime = System.currentTimeMillis();Object obj = proceedingJoinPoint.proceed();System.out.println("time aspect 耗时:" + (System.currentTimeMillis() - startTime));System.out.println("time aspect finish.");return obj;}
}
@Around 定义了环绕通知,也就是定义了何时使用切面,表达式"execution(* club.sscai.security.web.controller.UserController.*(..))"定义了再哪里使用。
ProceedingJoinPoint 对象的 proceed() 方法表示执行被拦截的方法,它有一个 Object 类型的返回值,是原有方法的返回值,后期使用的时候往往需要强转。
对于上面三种拦截方式,他们的执行有一个基本的顺序,进入的顺序是:
Filter-->Interceptor-->Aspect-->Controller-->Aspect-->Interceptor-->Filter(不考虑异常的发生)。
如下所示:

 

博客地址:http://www.cnblogs.com/niceyoo
posted @ 2018-12-22 19:02 niceyoo 阅读(...) 评论(...) 编辑 收藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/414599.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7、Flutter banner_view 轮播图的使用

7、Flutter banner_view 轮播图的使用 1、前言 实现轮播图,效果如下: 2、实现 将采用 banner_view 实现:资源库地址 2.1、yaml 引入依赖 在 pubspec.yaml 声明需要引用的库,执行命令 flutter packages get 进行拉取即可使用。 ba…

Android 人脸实名验证demo——腾讯人脸核身·云智慧眼

可以说比较容易实现:只需要获取BizToken,再起调腾讯SDK即可 1、首先登录腾讯云平台,申请权限,创建应用 腾讯云: https://cloud.tencent.com/ 2、配置应用信息及实名验证流程设置,下载SDK 不过,…

[JSOI 2015] 子集选取

4475: [Jsoi2015]子集选取 Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 363 Solved: 255[Submit][Status][Discuss]Description Input 输入包含一行两个整数N和K&#xff0c;1<N,K<10^9 Output 一行一个整数&#xff0c;表示不同方案数目模1,000,000,007的值。 Sam…

工作242:关于第二个git仓库提交代码

其实第二个仓库 建立的时候直接取进行 push操作就可以完成 原理一样 可以直接对代码地址进行提交

工作243:name报错

name报错就是name的数值报错

Android 图片压缩,Bitmap旋转,bitmap与byte[]之间相互转换,Bitmap与String互转

频繁setImageBitmap引起oom问题解决方法 Glide.with(gsewmimg).load(getCodeBitmap(response.data.skip, R.mipmap.zhifuicon)).into(gsewmimg);压缩前后。图片大小 2.22MB——>200KB 1、图片压缩方法&#xff1a; Bitmap bitmap; byte[] buff; buff Bitmap2Bytes(bitmap…

9、Flutter 实现 生成二维码

9、Flutter 实现 生成二维码 1、加入依赖 在 pubspec.yaml 中 dependencies 节点下添加&#xff1a; dependencies: qr_flutter: ^1.1.6 2、引入代码 在需要细线二维码的 dart 类中引入依赖代码包&#xff1a; import package:qr_flutter/qr_flutter.dart; 代码部分 import p…

Android 换肤demo,轻量快捷接入集成,判断是否夜间模式

true为黑夜模式 //检查当前系统是否已开启暗黑模式 public static boolean getDarkModeStatus(Context context) {int mode context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;return mode Configuration.UI_MODE_NIGHT_YES;} 实现…

Python——使用matplotlib绘制柱状图

Python——使用matplotlib绘制柱状图 1、基本柱状图 首先要安装matplotlib&#xff08;http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot&#xff09; 可以使用pip命令直接安装[python] view plaincopy # -*- coding: utf-8 -*- import matplotlib.pyplot a…

Android 语音播报,语音识别demo

该功能是基于百度智能云实现的根据文字进行语音播报。 1、首先到百度智能云创建语音应用 https://console.bce.baidu.com/ai/ 填写包名创建百度语音应用&#xff0c;获取AppID&#xff0c;API Key&#xff0c;Secret Key 2、导入资源文件。语音jar&#xff0c;assets语音库&am…

jeecg自定义按钮使用exp属性不起作用

jeecg自定义按钮使用exp属性不起作用 为什么要写这篇文章&#xff1f; 之前写过一篇类似的文章 jeecg笔记之自定义显示按钮exp属性&#xff0c;但是有些小伙伴留言参考后不起作用&#xff0c;当时我的 jeecg 版本为3.7.5&#xff0c;最终以版本不同&#xff0c;暂时搁浅了。今…

使用java修改图片DPI

修改以后可以直接用PS打开看效果 全部使用rt下的类&#xff0c;无需下载其他jar包 import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; import javax.imageio.ImageIO; …

Android studio 创建kotlin工程

1、安装kotlin插件 打开settings页面。安装插件 2、已安装kotlin插件即可创建kotlin项目 打开New Project。选中Includ Kotlin support即可 3、创建kotlin或者java的activity 选中语音类型kotlin或者java kotlin项目创建完成 kotlin工程demo链接&#xff1a;https://download…

改造一下jeecg中的部门树

改造一下jeecg中的部门树 假装有需求 关于 jeecg 提供的部门树&#xff0c;相信很多小伙伴都已经用过了&#xff0c;今天假装有那么一个需求 "部门树弹窗选择默认展开下级部门"&#xff0c;带着这个需求再次去探索一下吧。 一、改造之前的部门选择树流程 1.1 t:depa…

html 知识

一 html是什么&#xff1f; ,1、超文本标记语言&#xff08;Hypertext Markup Language, HTML&#xff09;是一种用于创建网页的标记语言。 2、本质上是浏览器可识别的规则&#xff0c;我们按照规则写网页&#xff0c;浏览器根据规则渲染我们的网页。对于不同的浏览器&#xff…

工作245:vue的注意规范之v-if 与 v-for 一起使用

当 v-if 与 v-for 一起使用时&#xff0c;v-for 具有比 v-if 更高的优先级&#xff0c;这意味着 v-if 将分别重复运行于每个 v-for 循环中 所以&#xff0c;不推荐v-if和v-for同时使用 使用推荐方式&#xff1a; 或者&#xff1a;放在计算属性遍历 当它们处于同一节点&#x…