SpringBoot实现过滤器、拦截器与切片

from pointnet2_ops import pointnet2_utils 安装过程 pointnet2_ops 阅读详情

 2020年最新的常问企业面试题大全以及答案

作者:七印miss

juejin.im/post/5c6901206fb9a049af6dcdcf

Q:使用过滤器、拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系

过滤器Filter

过滤器概念

Filter是J2E中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。

使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行预处理并生成响应,最后Filter再对服务器响应进行后处理。

过滤器作用

在JavaDoc中给出了几种过滤器的作用

  • Examples that have been identified for this design are

    1) Authentication Filters, 即用户访问权限过滤

    2) Logging and Auditing Filters, 日志过滤,可以记录特殊用户的特殊请求的记录等

    3) Image conversion Filters

    4) Data compression Filters

    5) Encryption Filters

    6) Tokenizing Filters

    7) Filters that trigger resource access events

    8) XSL/T filters

    9) Mime-type chain Filter

对于第一条,即使用Filter作权限过滤,其可以这么实现:定义一个Filter,获取每个客户端发起的请求URL,与当前用户无权限访问的URL列表(可以是从DB中取出)作对比,起到权限过滤的作用。

过滤器实现方式

自定义的过滤器都必须实现javax.Servlet.Filter接口,并重写接口中定义的三个方法:

1.void init(FilterConfig config)

用于完成Filter的初始化。

2.void destory()

用于Filter销毁前,完成某些资源的回收。

3.void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)

实现过滤功能,即对每个请求及响应增加的额外的预处理和后处理。,执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

值得注意的是,chain.doFilter()方法执行之前为预处理阶段,该方法执行结束即代表用户的请求已经得到控制器处理。因此,如果在doFilter中忘记调用chain.doFilter()方法,则用户的请求将得不到处理。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

// 必须添加注解,springmvc通过web.xml配置
@Component
public class TimeFilter implements Filter {
    private static final Logger LOG = LoggerFactory.getLogger(TimeFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOG.info("初始化过滤器:{}", filterConfig.getFilterName());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        LOG.info("start to doFilter");
        long startTime = System.currentTimeMillis();
        chain.doFilter(request, response);
        long endTime = System.currentTimeMillis();
        LOG.info("the request of {} consumes {}ms.", getUrlFrom(request), (endTime - startTime));
        LOG.info("end to doFilter");
    }

    @Override
    public void destroy() {
        LOG.info("销毁过滤器");
    }

    private String getUrlFrom(ServletRequest servletRequest){
        if (servletRequest instanceof HttpServletRequest){
            return ((HttpServletRequest) servletRequest).getRequestURL().toString();
        }

        return "";
    }
}

从代码中可看出,类Filter是在javax.servlet.*中,因此可以看出,过滤器的一个很大的局限性在于,其不能够知道当前用户的请求是被哪个控制器(Controller)处理的,因为后者是spring框架中定义的。

在SpringBoot中注册第三方过滤器

对于SpringMvc,可以通过在web.xml中注册过滤器。但在SpringBoot中不存在web.xml,此时如果引用的某个jar包中的过滤器,且这个过滤器在实现时没有使用@Component标识为Spring Bean,则这个过滤器将不会生效。

此时需要通过java代码去注册这个过滤器。以上面定义的TimeFilter为例,当去掉类注解@Component时,注册方式为:

@Configuration
public class WebConfig {
    /**
     * 注册第三方过滤器
     * 功能与spring mvc中通过配置web.xml相同
     * @return
     */
    @Bean
    public FilterRegistrationBean thirdFilter(){
        ThirdPartFilter thirdPartFilter = new ThirdPartFilter();
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean() ;

        filterRegistrationBean.setFilter(thirdPartFilter);
        List<String > urls = new ArrayList<>();
        // 匹配所有请求路径
        urls.add("/*");
        filterRegistrationBean.setUrlPatterns(urls);

        return filterRegistrationBean;
    }
}

相比使用@Component注解,这种配置方式有个优点,即可以自由配置拦截的URL。

拦截器Interceptor

拦截器概念

拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。

拦截器作用

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等

  • 权限检查:如登录检测,进入处理器检测检测是否登录

  • 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如apache也可以自动记录);

  • 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

拦截器实现

通过实现HandlerInterceptor接口,并重写该接口的三个方法来实现拦截器的自定义:

1.preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)

方法将在请求处理之前进行调用。SpringMVC中的Interceptor同Filter一样都是链式调用。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。

该方法的返回值是布尔值Boolean 类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。

2.postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。

3.afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)

该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

@Component
public class TimeInterceptor implements HandlerInterceptor {
    private static final Logger LOG = LoggerFactory.getLogger(TimeInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOG.info("在请求处理之前进行调用(Controller方法调用之前)");
        request.setAttribute("startTime", System.currentTimeMillis());
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        LOG.info("controller object is {}", handlerMethod.getBean().getClass().getName());
        LOG.info("controller method is {}", handlerMethod.getMethod());

        // 需要返回true,否则请求不会被控制器处理
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        LOG.info("请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后),如果异常发生,则该方法不会被调用");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        LOG.info("在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
        long startTime = (long) request.getAttribute("startTime");
        LOG.info("time consume is {}", System.currentTimeMillis() - startTime);
    }

与过滤器不同的是,拦截器使用@Component修饰后,在SpringBoot中还需要通过实现WebMvcConfigurer手动注册:

// java配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private TimeInterceptor timeInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(timeInterceptor);
    }
}

如果是在SpringMVC中,则需要通过xml文件配置<mvc:interceptors>节点信息。

切片Aspect

切片概述

相比过滤器,拦截器能够知道用户发出的请求最终被哪个控制器处理,但是拦截器还有一个明显的不足,即不能够获取request的参数以及控制器处理之后的response。所以就有了切片的用武之地了。

切片实现

切片的实现需要注意@Aspect,@Component以及@Around这三个注解的使用,详细查看官方文档:

https://docs.spring.io/spring/docs/5.0.12.RELEASE/spring-framework-reference/core.html#aop

@Aspect
@Component
public class TimeAspect {
    private static final Logger LOG = LoggerFactory.getLogger(TimeAspect.class);

    @Around("execution(* me.ifight.controller.*.*(..))")
    public Object handleControllerMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        LOG.info("切片开始。。。");
        long startTime = System.currentTimeMillis();

        // 获取请求入参
        Object[] args = proceedingJoinPoint.getArgs();
        Arrays.stream(args).forEach(arg -> LOG.info("arg is {}", arg));

        // 获取相应
        Object response = proceedingJoinPoint.proceed();

        long endTime = System.currentTimeMillis();
        LOG.info("请求:{}, 耗时{}ms", proceedingJoinPoint.getSignature(), (endTime - startTime));
        LOG.info("切片结束。。。");
        return null;
    }
}

过滤器、拦截器以及切片的调用顺序

如下图,展示了三者的调用顺序Filter->Intercepto->Aspect->Controller。相反的是,当Controller抛出的异常的处理顺序则是从内到外的。因此我们总是定义一个注解@ControllerAdvice去统一处理控制器抛出的异常。

如果一旦异常被@ControllerAdvice处理了,则调用拦截器的afterCompletion方法的参数Exception ex就为空了。

实际执行的调用栈也说明了这一点:

而对于过滤器和拦截器详细的调用顺序如下图:

过滤器和拦截器的区别

最后有必要再说说过滤器和拦截器二者之间的区别:

除此之外,相比过滤器,拦截器能够“看到”用户的请求具体是被Spring框架的哪个控制器所处理。

参考

https://blog.youkuaiyun.com/xiaodanjava/article/details/32125687

(完)

推荐阅读:

如何在面试中介绍自己的项目经验?

Git 从入门到精通,这篇包教包会!

2020 年 9 大顶级 Java 框架

130 个相见恨晚的超实用网站,一次性分享出来

好文!必须点赞
Hexo博客使用PDF.js clone了一个pdf.js 然后兴高采烈地到文章里使用{% pdf %}标签 结果浏览器弹出了个下载框(使用GitHub的raw) 不知道是不是因为使用GitHub的原因导致这个问题 后来我测试的时候报了个错 优快云上的解决方法 到时候我再试试把资源放回lib/里面看看行不行 目录1.clone1.1.官方方法1.2.NexT主题方法1.3.补充2.修改文件2.1.修改viewer.htm... 阅读详情

相关推荐

麒麟操作系统安装达梦数据库ARM版

Linux安装达梦数据库ARM版

运维@小兵的博客 8770

Spring boot 集成 servlet、监听器、过滤器、拦截器

Spring boot 集成 servlet Web 开发使用 Controller 基本上可以完成大部分需求,但是我们还可能会用到 Servlet、Filter、Listener、Interceptor 等等。 当使用 Spring-Boot 时,嵌入式 Servlet 容器通过扫描注解的方式注册 Servlet、Filter 和 Servlet 规范的所有监听器(如HttpSessionListener 监听器)。 Spring boot 的主 Servlet 为 DispatcherServlet,其

weixin_44740485的博客 543

Arduino程序设计(十四)舵机控制实验(SG90)

本文介绍SG90舵机控制原理及实验,主要内容有:1、介绍SG90舵机;2、舵机0°~180°来回转动;3、串口控制舵机转动固定角度。(1)舵机是一种位置(角度)伺服的驱动器。舵机只是一种通俗的叫法,其实质是一个伺服马达。在需要角度不断变化并可以保持的控制系统中应用广泛。如遥控机械人、飞机模型等。(2)舵机的转动角度为0~180°,其内部结构包括电机,控制电路和机械结构三部分。电机有三根线引出,分别接VCC、GNG和信号线。

Alice的博客 1万+

SpringBoot:整合监听器/过滤器和拦截器

在实际开发过程中,经常会碰见一些比如系统启动初始化信息、统计在线人数、在线用户数、过滤敏/高词汇、访问权限控制(URL级别)等业务需求。实现以上的功能,都会或多或少的用到过滤器、监听器、拦截器。

qq_43842093的博客 1271

ESP32驱动TFT屏幕实战:LVGL与TFT_eSPI完美结合

本文详细介绍了如何在ESP32上结合TFT_eSPI驱动库与LVGL图形库,实现高效、流畅的嵌入式GUI开发。内容涵盖硬件连接、软件环境搭建、库配置、LVGL移植、界面创建及性能优化等全流程实战指南,帮助开发者快速构建低成本、高性能的交互式显示应用。

weixin_29206669的博客 200

AutoSAR配置视频讲解:简介

AutoSAR实验视频讲解:闪烁一颗LED实验【简介】 大家好,欢迎来到雪云飞星的《AutoSAR实验课的视频讲解》专栏。看过《AutoSAR入门到精通系列讲解》的朋友们应该对博主不陌生,有很多朋友加了博主的微信成为了好友,还有朋友约过线下见面,博主很高兴大家能从我的博客中获得一些收获。在专栏里博主挖了很多坑,当时也说过想要录制一个AutoSAR的配置视频教程,素材在20年初就已经录好,中间各种原因足足鸽了一年。当时因为一些技术原因只能通过博客的图文形式展示出来,现在我们剪辑了视频,请了专业的配音,希望以视

雪云飞星的博客 9657

Spring Boot 实现过滤器、拦截器与切片

作者 | 七印miss链接 | juejin.im/post/5c6901206fb9a049af6dcdcfQ: 使用过滤器、拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系...

公众号:Java后端 1543

【PCIe EP 设备入门学习专栏 -- 8 PCIe EP 架构详细介绍】

Synopsys PCIe 5.0 EP 架构由多个功能模块组成,整体遵循分层 + 模块化设计CXPL(事务层 + 链路层 + 物理层 MAC)XADM(仲裁/生成)、XAIM(应用接口)RADM(过滤/路由/Completion)CDM(配置空间)、PMC(电源管理)、LBC/DBI(寄存器访问)MSG_GEN(消息)、CXS(多芯片一致性)

CodingCos的博客 384

Springboot实现拦截器与过滤器

概述 Springboot实现拦截器与过滤器的方法网上很多文章,本文主要阐述实际实现拦截器过程中踩的一下坑. 1.拦截器 1.1.创建拦截器 1.1.1 实现HandlerInterceptor package com.qihang.springdemo.interceptor; import com.qihang.springdemo.threadlocal.LoginInfoContext; import com.qihang.springdemo.threadlocal.LoginThreadLo

qq_41999004的博客 1943

地图之家总目录

地图之家总目录 cesium示例 leaflet示例

GIS之家家长 1万+

从泛光成像到可寻址扫描:Flash激光雷达的车规级优势与技术演进

Flash激光雷达凭借固态架构优势成为自动驾驶感知技术的重要发展方向。该方案无机械部件,具备抗振动、长寿命等特点,同时CMOS工艺带来显著成本优势。但传统泛光式存在能量弥散问题,难以兼顾大视场和远距离探测。可寻址扫描技术通过分区点亮VCSEL阵列,有效提升局部能量密度,在保持固态可靠性的同时突破性能瓶颈。这种"电子扫描+分区点亮"的混合架构,使Flash激光雷达有望实现大视场、远距离、高可靠和低成本的多重突破,推动自动驾驶技术发展。

致力于lidar应用开发 235

Spring Boot 拦截器

上一篇对过滤器的定义做了说明,也比较简单。过滤器属于Servlet范畴的API,与Spring 没什么关系。 Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Spring提供的HandlerInterceptor(拦截器)。HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在request被响应之前、request被响应之后、视图渲染之前

小单的博客专栏 16万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

springboot 拦截器_SpringBoot实现过滤器、拦截器与切片

Q:使用过滤器、拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系过滤器Filter过滤器概念Filter是J2E中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对用户请...

weixin_39732249的博客 80

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java切片_说得太好了!Spring Boot如何实现过滤器、拦截器与切片?

推荐阅读:Sping源码+Redis+Nginx+MySQL等七篇实战技术文档,阿里大佬推荐阿里“善用”的Java分布式架构精髓,全部分享在这一份PDF里了Q:使用过滤器、拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系过滤器Filter过滤器概念Filter是J2E中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filte...

weixin_39621235的博客 95

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

java切片_实战 | SpringBoot实现过滤器、拦截器与切片

作者:七印missjuejin.im/post/5c6901206fb9a049af6dcdcfQ:使用过滤器、拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系过滤器Filter过滤器概念Filter是J2E中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实...

weixin_39923262的博客 242

Spring Boot如何实现过滤器、拦截器与切片?

对于SpringMvc,可以通过在web.xml中注册过滤器。但在SpringBoot中不存在web.xml,此时如果引用的某个jar包中的过滤器,且这个过滤器在实现时没有使用@Component标识为Spring Bean,则这个过滤器将不会生效。 此时需要通过java代码去注册这个过滤器。以上面定义的TimeFilter为例,当去掉类注解@Component时,注册方式为: @Configur...

鲸落的博客 312

在拦截器里放入参数 controller_SpringBoot实现过滤器、拦截器与切片

Q:使用过滤器、拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系 过滤器Filter 过滤器概念 Filter是J2E中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对...

weixin_39797264的博客 1375

SpringBoot实现过滤器、拦截器与切片源码分析

过滤器Filter 过滤器概念 Filter是J2E中来的,可以看做是Servlet的一种“加强版”,它主要用于对用户请求进行预处理和后处理,拥有一个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行预处理并生成响应,最...

coding_1994的博客 437
上一篇: 如何在面试中介绍自己的项目经验?
下一篇: 程序员 6 个接私活的网站,你有技术就有钱!
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值