Filter

新建 TimeFilter

@Component
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("time filter init");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("time filter start");
long startTime = System.currentTimeMillis(); filterChain.doFilter(servletRequest, servletResponse); long endTime = System.currentTimeMillis();
System.out.println("time filter consume " + (endTime - startTime) + " ms");
System.out.println("time filter end");
} @Override
public void destroy() {
System.out.println("time filter init");
}
}

启动服务器,在浏览器输入:http://localhost:8080/hello?name=tom

可以在控制台输出如下结果:

time filter start

name: tom

time filter consume 3 ms

time filter end

可以看到,filter 先执行,再到真正执行 HelloController.sayHello() 方法。

通过 TimeFilter.doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) 方法的参数可以看出,我们只能得到原始的 request 和 response对象,不能得到这个请求被哪个 Controller 以及哪个方法处理了,使用Interceptor 就可以获得这些信息。

Interceptor

新建 TimeInterceptor

@Component
public class TimeInterceptor extends HandlerInterceptorAdapter { private final NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("startTimeThreadLocal"); @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("time interceptor preHandle"); HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取处理当前请求的 handler 信息
System.out.println("handler 类:" + handlerMethod.getBeanType().getName());
System.out.println("handler 方法:" + handlerMethod.getMethod().getName()); MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
for (MethodParameter methodParameter : methodParameters) {
String parameterName = methodParameter.getParameterName();
// 只能获取参数的名称,不能获取到参数的值
//System.out.println("parameterName: " + parameterName);
} // 把当前时间放入 threadLocal
startTimeThreadLocal.set(System.currentTimeMillis()); return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("time interceptor postHandle");
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 从 threadLocal 取出刚才存入的 startTime
Long startTime = startTimeThreadLocal.get();
long endTime = System.currentTimeMillis(); System.out.println("time interceptor consume " + (endTime - startTime) + " ms"); System.out.println("time interceptor afterCompletion");
}
}

注册 TimeInterceptor

把 TimeInterceptor 注入 spring 容器

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter { @Autowired
private TimeInterceptor timeInterceptor; @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}

启动服务器,在浏览器输入:http://localhost:8080/hello?name=tom

可以在控制台输出如下结果:

time filter start
time interceptor preHandle
handler 类:com.nextyu.demo.web.controller.HelloController
handler 方法:sayHello
name: tom
time interceptor postHandle
time interceptor consume 40 ms
time interceptor afterCompletion
time filter consume 51 ms
time filter end

可以看到,filter 先于 interceptor 执行,再到真正执行 HelloController.sayHello() 方法。通过 interceptor 方法上的 handler 参数,我们就可以得到这个请求被哪个 Controller 以及哪个方法处理了。但是不能直接获取到这个方法上的参数值(在这里就是 HelloController.sayHello(String name) 方法参数 name 的值),通过 Aspect 就可以获取到。

Aspcet

新建 TimeAspect

@Aspect
@Component
public class TimeAspect { @Around("execution(* com.nextyu.demo.web.controller.*.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("time aspect start"); Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println("arg is " + arg);
} long startTime = System.currentTimeMillis(); Object object = pjp.proceed(); long endTime = System.currentTimeMillis();
System.out.println("time aspect consume " + (endTime - startTime) + " ms"); System.out.println("time aspect end"); return object;
} }

启动服务器,在浏览器输入:http://localhost:8080/hello?name=tom

可以在控制台输出如下结果:

time filter start
time interceptor preHandle
handler 类:com.nextyu.demo.web.controller.HelloController
handler 方法:sayHello
time aspect start
arg is tom
name: tom
time aspect consume 0 ms
time aspect end
time interceptor postHandle
time interceptor consume 2 ms
time interceptor afterCompletion
time filter consume 4 ms
time filter end

可以看到,filter 先执行,再到 interceptor 执行,再到 aspect 执行,再到真正执行 HelloController.sayHello() 方法。

我们也获取到了 HelloController.sayHello(String name) 方法参数 name 的值

请求拦截过程图

graph TD
httprequest-->filter
filter-->interceptor
interceptor-->aspect
aspect-->controller

spring里的三大拦截器的更多相关文章

  1. Spring AOP原理及拦截器

    原理 AOP(Aspect Oriented Programming),也就是面向方面编程的技术.AOP基于IoC基础,是对OOP的有益补充. AOP将应用系统分为两部分,核心业务逻辑(Core bu ...

  2. Spring Boot2(七):拦截器和过滤器

    一.前言 过滤器和拦截器两者都具有AOP的切面思想,关于aop切面,可以看上一篇文章.过滤器filter和拦截器interceptor都属于面向切面编程的具体实现. 二.过滤器 过滤器工作原理 从上图 ...

  3. spring boot 过滤器、拦截器的区别与使用

    原文:https://blog.csdn.net/heweimingming/article/details/79993591 拦截器与过滤器的区别: 1.过滤器和拦截器触发时机不一样,过滤器是在请求 ...

  4. spring mvc中的拦截器小结 .

    在spring mvc中,拦截器其实比较简单了,下面简单小结并demo下. preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Control ...

  5. spring boot 实现mybatis拦截器

    spring boot 实现mybatis拦截器 项目是个报表系统,服务端是简单的Java web架构,直接在请求参数里面加了个query id参数,就是mybatis mapper的query id ...

  6. Spring的一种拦截器SimpleUrlHandlerMapping

    spring的一种拦截器,用于在XML文件中配置以拦截url,它是以map映射的方式进行拦截.映射是从前台urls到具体后台的beans.同时支持到bean实例和bean名称的映射,后者要求非单实例控 ...

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

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

  8. spring boot中注册拦截器

    拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重 ...

  9. Spring Mvc 的自定义拦截器

     spring mvc的拦截器 SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户 ...

随机推荐

  1. mip-link 组件功能升级说明

    背景描述 某个页面被多少页面引用(在其他页面上有指向这个页面的 a 标签),是搜索引擎判断这个页面价值的其中一个因子.这里的搜索引擎不只是指百度,还包括国内外其他的搜索引擎. MIP 在最初设计 MI ...

  2. RabbitMQ和Kafka到底怎么选?

    前言 开源社区有好多优秀的队列中间件,比如RabbitMQ和Kafka,每个队列都貌似有其特性,在进行工程选择时,往往眼花缭乱,不知所措.对于RabbitMQ和Kafka,到底应该选哪个? Rabbi ...

  3. 怎么构建vue-cli项目

    1.安装node.js(已安装可直接跳过,建议查看node版本,node -v): 2.npm包管理器,是集成在node中的,可跳过(npm -v): 3.由于npm的有些资源被墙,为了更快更稳定,所 ...

  4. KnockoutJS知识规整目录

    对于Web开发来讲,前端接触是避免不了的,特别是对于中小公司,没有严格的职位区分,前后端人员互相身兼是常有的事情,使用一些好的框架,能够帮助我们快速开发并完成需要的功能,对于前端的JS框架来讲MVVM ...

  5. Electron学习笔记(一)

    Electron是使用Javascript.HTML5技术构建跨平台桌面应用的技术,是目前非常活跃的一项技术,其中比较有名气的应用有微软的VS Code. 创建一个Electron应用的方式有很多,G ...

  6. 关于vue使用form上传文件

    在vue中使用form表单上传文件文件的时候出现了一些问题,获取文件的时候一直返回null, 解决之后又出现发送到后台的file文件后台显示为空,解决源码 <template> <d ...

  7. .Net 事件总线之Autofac解耦

    事件总线是通过一个中间服务,剥离了常规事件的发布与订阅(消费)强依赖关系的一种技术实现.事件总线的基础知识可参考圣杰的博客[事件总线知多少] 本片博客不再详细概述事件总线基础知识,核心点放置使用Aut ...

  8. C#操作符??,?,?:功能解析

    ??操作符:叫做空合并操作符,它会对左右两个操作数进行判断,如果左边的数不为空,就返回左边的数,否则返回右边的数. ?操作符:语法糖,表示可空类型,可空类型也是值类型,它是包含null值的值类型,可通 ...

  9. Hibernate学习——持久化类的学习

    A.概念 持久化:将内存中的对象持久化(存储)到数据库的过程.Hibernate就是持久化的框架. 持久化类:一个普通java对象与数据库的表建立了映射关系,那么这个类在Hiberna中被称为持久化类 ...

  10. mysql 多实例部署

    Centos7.6 部署3个Mariadb 实例 [root@localhost ~]# yum install mariadb-server -y # 创建对应的目录文件 [root@localho ...