首页 > 其他分享 >过滤器和拦截器的辨析

过滤器和拦截器的辨析

时间:2024-03-11 10:23:40浏览次数:28  
标签:拦截器 辨析 request 过滤器 Servlet response processedRequest

过滤器和拦截器的辨析

介绍

过滤器和拦截器都是为了在请求到达目标处理器(Servlet或Controller)之前或者之后插入自定义的处理逻辑

  • 过滤器:

遵循AOP(面向切面编程)思想实现,基于Servlet规范提供的Filter接口,它是位于客户端请求与服务器响应之间的一个组件,依赖于Servlet容器。当请求到达服务器时,过滤器会在请求进入实际目标资源(如Servlet、JSP页面)之前或之后执行特定的操作,原理是基于函数回调

  • 拦截器

遵循AOP(面向切面编程)思想实现,如Spring MVC中的HandlerInterceptor接口,它不依赖于Servlet容器的具体实现,而是由应用框架管理。拦截器是在请求进入到控制器层(Controller)方法前后执行自定义逻辑

原理解析

过滤器

为什么说过滤器基于函数回调?

过滤器基于函数回调,所谓函数回调/回调函数指的是:一个函数(称为回调函数)作为参数传递给另一个函数(称为调用函数),当满足一定条件或者在某个特定时刻,调用函数会调用传递过来的回调函数

由于Java中不直接支持函数指针,所以常常通过接口来实现回调机制

FilterChain就是一个接口

public interface FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}

Filter的实现类中doFilter()方法中FilterChain作为参数被传进来,并且在合适的时机被回调了其doFilter方法

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("hello");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

拦截器

拦截器基于AOP(面向切面编程)思想实现,但是并不一定用到动态代理或者切面,切点之类的技术,以如Spring MVC中的HandlerInterceptor接口为例,从源码看更像是直接将拦截器注入,形成了一个拦截器链,在controller层面上进行代码织入

DispatcherServlet作为SpringMVC框架的核心类,http请求的核心执行方法为doService(),再进入doDispatch()方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
        /**
         * 1.
         * HandlerExecutionChain 是一个对象
         * 包含了以下重要的属性
         * private final Object handler; //处理器(controller和其最后的方法)
         * List<HandlerInterceptor> interceptorList = new ArrayList<>();//拦截器列表,用来存储匹配处理器的拦截器
         */
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

                /**
                 * 2.
                 * 下面这行代码 大概做了以下事情
                 * 1.通过request和url 匹配了对应的controller以及调用的方法 填充了HandlerExecutionChain.handler
                 * 2.通过匹配request和HandlerInterceptor的注册信息(拦截哪些,放行哪些),往HandlerExecutionChain.interceptorList中添加对应的拦截器
                 */
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
                /**
                 * 3.执行 拦截器链条中的所有前置方法
                 */
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

                /**
                 * 4.交由处理器(controller对应的方法)去处理方法中的业务逻辑
                 */
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
                
                /**
                 * 5.倒序执行 拦截器链条中的所有后置方法
                 */
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}}
        //...

流程解析

由于Filter依赖于Servlet容器所以不同的容器Filter,FilterChain的实现类存在差异,这里以Tomcat为例分析

1.向后台发起一次请求

2.接待线程接收到,将任务转交给工作线程

3.判断协议,封装必要对象

4.将request,response一路转交至StandardWrapperValve.invoke(Request request, Response response)

5.创建过滤链ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

​ 5.1从上下文中获取注册好的过滤器

​ 5.2遍历过滤器,匹配URL,Servlet等,将匹配好的过滤器加入到过滤器链

6.依次回调FilterChain的doFilter方法filterChain.doFilter(request.getRequest(),response.getResponse());

7.将所有过滤器的前置代码执行完毕,进入servlet,servlet.service(request, response);

8.进入DispatcherServlet统一调度

9.调用拦截器前置方法

10.进入controller中的对应方法,执行具体的业务逻辑

11.调用拦截器后置(数组倒序执行)

12.将所有过滤器的后置代码执行完毕(方法栈,先进后出)

13.将结果返回给请求者

注意,过滤器和拦截器实现先进后出的实现方式是不同的,过滤器基于函数回调,方法栈结构天生支持先进后出;拦截器则是直接使用循环倒序遍历

总结

同:

  • 过滤器和拦截器都遵循面向切面编程的思想(AOP),实现了在请求到达目标处理器(Servlet/Controller)之前或者之后插入自定义的处理逻辑

异:

  • 使用范围不同

    过滤器实现的是javax.servlet.Filter该接口在Servlet规范中定义,依赖WEB容器

    拦截器是一个Spring组件,由Spring管理,并不依赖Tomcat容器,可以单独使用(Application,Swing)

  • 使用的场景不同

    拦截器更加接近业务系统,所以拦截器更适用于处理统一的业务逻辑,比如权限判断等

    过滤器通常用来实现通用功能,比如xss过滤,敏感词,处理跨域等等

  • 触发的时机不同

    过滤器的触发时机早于拦截器

  • 底层实现细节不同

    过滤器实现先进后出基于方法栈的数据结构

    拦截器实现先进后出基于循环倒序遍历

标签:拦截器,辨析,request,过滤器,Servlet,response,processedRequest
From: https://www.cnblogs.com/void-cmy/p/18065471

相关文章

  • java springboot拦截器的实现及用法
     1.前景,有时候我们在不同的地方需要使用用户的信息,我们可以使用threadLocal存储信息,这样我们在在这个线程随时使用用户信息了,不用自己在写一段冗余代码了,这时候使用拦截器就很不错 2.实现1.实现HandlerInterceptor2.重写实现方法  preHandle:在业务处理器处理请......
  • 辨析Java与网络通信中的编码与解码
    在Java字符流上下文中的编码和解码,以及在网络通信中的编码概念。在Java中,当我们谈论字符流(如Reader和Writer)时,编码和解码主要涉及将字符数据转换为字节数据,以及将字节数据转换回字符数据。这是因为字符在计算机内部是以字节的形式存储和传输的,而字符流提供了一种更高级别的抽象,使......
  • 过滤器
    @WebFilter("/*")publicclassFileimplementsFilter{publicvoidinit(FilterConfigfilterConfig)throwsServletException{System.out.println("初始化过滤器");}publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletRes......
  • java过滤器拦截路劲问题
    在我们使用filter过滤器时注解@WebFilter("/serverlet/demo1/")多层目录只针对文件注解@WebServlet(name="Servlet1",value="/serverlet/demo1/test1")具有过滤作用(原因:注解路径相同),其中“@WebFilter("/serverlet/demo1/")”括号里的*代表只要serverlet注解前半部分相同的文......
  • (转)gRPC 拦截器
    原文:https://www.cnblogs.com/rickiyang/p/14975552.htmlGogRPC学习系列:跟我一起学Go系列:gRPC入门必备第一篇内容我们已经基本了解到gRPC如何使用、对应的三种流模式。现在已经可以让服务端和客户端互相发送消息。本篇仍然讲解功能性的使用说明:如何使用拦截器。使用过......
  • 黑马程序员JavaWeb学习笔记-过滤器
    过滤器--Filter过滤器Filter快速入门Filter拦截路径过滤器链Filter——流程importcom.alibaba.fastjson.JSONObject;importcom.itheima.pojo.Result;importlombok.extern.slf4j.Slf4j;importorg.springframework.util.StringUtils;importjavax.servlet.*;im......
  • 黑马程序员JavaWeb学习笔记-拦截器
    拦截器--Interceptor--快速入门@Component注解交给ioc容器管理--注册配置拦截器@Configuration注解用来标识当前是Spring当中的一个配置类//Interceptor拦截所有("/**")//Filter拦截所有("/*")//WebConfig需要在包下新建一个config包与controller同级//.excl......
  • Java 辨析之实例化和初始化
    在面向对象编程中,实例化和初始化是两个相关但不同的概念:实例化(Instantiation):实例化是指创建一个类的新的具体对象的过程。当程序运行时,通过new关键字调用类的构造函数来创建该类的一个实例。例如,在Java中:MyClassmyObject=newMyClass();在这行代码中,newMyClass()就是......
  • Vue 2x 系列之(十五)过滤器
    过滤器BootCDN:包含了一些免费、优秀的第三方类库官网:https://www.bootcdn.cn/moment.js:js的日期处理类库dayjs:moment.js的轻量化解决方案,API同moment.js完全一致引入dayjs,全局就多了一个dayjs()函数,dayjs()函数默认解析当前时间的时间戳,也可传入时间戳进行解析注:过滤器相对......
  • Vue学习笔记25--过滤器(日期格式化)
    日期格式化日期格式化插件:https://www.bootcdn.cn/moment.js、day.js(轻量级moment.js)插件用法:双击day.js==>复制链接并访问==》另存为dayjs.min==》项目中引用https://github.com/iamkun/dayjs/blob/dev/docs/zh-cn/README.zh-CN.md过滤器总结:定义:对要显示的数据进行......