文章前言

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

1、Filter 过滤器

1.1、方法说明

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

1.2、代码部分

@Component //表明作为spring的一个bean
public class TimeFilter implements Filter { @Override
public void destroy() {
System.out.println("time filter destroy");
} @Override
public 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");
} @Override
public 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 { @Override
public 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;
} @Override
public 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)); } @Override
public 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")
@Autowired
private TimeInterceptor timeInterceptor; // 拦截器的一个注册器
@Override
public 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
 

记录请求的耗时(拦截器、过滤器、aspect)的更多相关文章

  1. Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求

    Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 >>>>>>>>>>>>>>&g ...

  2. Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求

    Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,java 判断请求是不是ajax请求   Java过滤器处理Ajax请求,Java拦截器处理Ajax请求,拦截器Ajax请求 java ...

  3. 【springboot】过滤器、监听器、拦截器,Aspect切片

    转自: https://blog.csdn.net/cp026la/article/details/86501019 简介: 本章介绍拦截器.过滤器.切片对请求拦截的使用与区别,以及监听器在 spri ...

  4. spring拦截器-过滤器的区别

    1.  理解 拦截器 :是在面向切面编程的时候,在你的 service 或者一个方法前调用一个方法,或者在方法后调用一个方法:比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业 ...

  5. ava中拦截器 过滤器 监听器都有什么区别

    过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts2的action进行业务逻辑,比如过滤掉非法u ...

  6. XML文档形式&JAVA抽象类和接口的区别&拦截器过滤器区别

    XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? a: 两种形式 dtd schemab: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发 ...

  7. Struts2之Action接收请求参数和拦截器

    技术分析之在Struts2框架中使用Servlet的API        1. 在Action类中也可以获取到Servlet一些常用的API        * 需求:提供JSP的表单页面的数据,在Ac ...

  8. Struts2.0 封装请求数据和拦截器介绍

    1. Struts2 框架中使用 Servlet 的 API 来操作数据 1.1 完全解耦合的方式 Struts2 框架中提供了一个 ActionContext 类,该类中提供了一些方法: stati ...

  9. Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用

    一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filter这种方式可以实现Bean预处理.后处理. 比如注入FilterRegistrationBean,然后 ...

随机推荐

  1. FM算法(一):算法理论

    主要内容: 动机 FM算法模型 FM算法VS 其他算法   一.动机 在传统的线性模型如LR中,每个特征都是独立的,如果需要考虑特征与特征直接的交互作用,可能需要人工对特征进行交叉组合:非线性SVM可 ...

  2. JDK 8 函数式编程入门

    目录 1. 概述 1.1 函数式编程简介 1.2 Lambda 表达式简介 2. Lambda 表达式 2.1 Lambda 表达式的形式 2.2 闭包 2.3 函数接口 3. 集合处理 3.1 St ...

  3. Linux 目录结构和常用命令

    Linux目录结构 目录 说明 bin 存放二进制可执行文件(ls,cat,mkdir等) boot 存放用于系统引导时使用的各种文件 dev 用于存放设备文件 etc 存放系统配置文件 home 存 ...

  4. docker - 容器lxc

    容器:是在用户空间进行隔离的组件叫做容器 常用的容器有lxc ----libcontainer---runc 需要隔离的资源有: Rootfs:每个容器对应的一个目录做为根目录 User: Hostn ...

  5. kvm虚拟化2-qemu-kvm

    Kvm  只支持x86 64的硬件虚拟化    要求cpu必须支持硬件虚拟化 HVM Kvm两个组件: 1 kvm.ko模块装入后为/dev/kvm 工作为hypervisor ,在用户空间通过系统调 ...

  6. Linux安装Tomcat-Nginx-FastDFS-Redis-Solr-集群——【第九集-补充-之安装mariadb】

    由于也是第一次安装,再此不必献丑了,贴上参考链接: 1,指导我为什么使用mariadb而不是用mysql:https://blog.csdn.net/liumiaocn/article/details ...

  7. easy-ui 中的事件触发 (tree)

    easy-ui可以为插件添加事件,但没有触发事件的处理(可能是未找到),所以有时候,我们需要通过程序去触发某个插件指定的事件时,就一筹莫展了 以Tree插件为例 ,添加了onClick事件 jQuer ...

  8. 问题10:获取当前页面宽度JS

    var mleft=document.getElementById("mleft"); var h = document.documentElement.clientHeight; ...

  9. scrapy流程

  10. python中matplotlib画图

    参考 https://blog.csdn.net/u010358304/article/details/78906768 https://www.cnblogs.com/onemorepoint/p/ ...