文章前言

记录控制器请求的耗时处理通常有三种实现方式,分别是:过滤器、拦截器、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. Python——python读取html实战,作业7(python programming)

    查看源码,观察html结构 # -*- coding: utf-8 -*- from lxml.html import parse from urllib.request import urlopen ...

  2. css clip-path的polygon属性绘制多边形

    通过设置多个点的坐标位置来绘制图形的形状 .box{ clip-path:polygon(x1 y1, x2 y2, x3 y3, , , , , ,) backgroud-color:red; }

  3. Apache服务器中设置端口映射和反向代理的方法

    在/etc/httpd/conf路径下的httpd.conf文件###new add for webui.cong###Include "E:/local/Wamp/bin/apache/A ...

  4. 必须知道的Linux内核常识详解

    一.内核功能.内核发行版 1.到底什么是操作系统 (1)linux.windows.android.ucos就是操作系统: (2)操作系统本质上是一个程序,由很多个源文件构成,需要编译连接成操作系统程 ...

  5. 禁用大陆ip段

    https://www.ip2location.com/free/visitor-blocker 有 .htaccess web.config等 以iis为例 打开C:\Windows\System3 ...

  6. 【redis】-- springboot集成redis及使用

    springboot自动配置的redis并不是特别好用,所以需要我们使用原生的jedis, 1.添加依赖 2.在application文件中配置 # Redis服务器地址 redis.host= # ...

  7. Beta(5/7)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...

  8. tap穿透之zepto的bug

    一.什么是zepto tap事件穿透?tap事件穿透就是,页面和弹框上都有绑定点击事件,最上层的弹框绑定了tap事件,下层的页面绑定了click事件,在执行完上层事件后会紧接着触发下层事件,进而出现事 ...

  9. 17使用systemd方式开机自动启动Home Assistant服务

    2018-03-20 15:48:36 转移自网易博客! 首先使用编写文件hass@homeassistant.service,文件内容如下 # 这个文件用于systemd方式自动启动hass服务.# ...

  10. Lock锁方式解决线程安全问题

    在JDK5.0之后新增加了一种更强大的线程同步机制---通过显示定义同步锁来实现线程同步解决线程安全问题.同步锁使用Lock对象充当. java.util.concurrent.locks.lock接 ...